本文共 9095 字,大约阅读时间需要 30 分钟。
在 Java 开发中,JDBC 是连接数据库的重要工具。通过 JDBC,我们可以通过 Java 程序与各种关系型数据库进行交互。本文将介绍 JDBC 的基本使用方法,并结合实例展示如何将 JDBC 返回值直接包装到实体类中。
JDBC 提供了标准化的接口,使开发者能够通过 Java 程序访问各种数据库。以下是 JDBC 的基本使用步骤:
DriverManager.getConnection()
获取数据库连接。Statement
或 PreparedStatement
对数据库进行查询。ResultSet
) 将数据转换为 Java 对象。在实际开发中,数据库查询的结果通常以字段形式返回,而我们需要将这些字段映射到 JavaBean 对应的属性中。本文提供了一个简单的 Student 实体类:
package cn.dbutils.analyze;public class Student { private Integer id; private String name; private Date time; public Student() { super(); } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getTime() { return time; } public void setTime(Date time) { this.time = time; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", time=" + time + "]"; }}
为了简化 JDBC 的复杂性,我们开发了一个 QueryRunner
工具类。以下是工具类的核心逻辑:
public class QueryRunner { private Connection con; public QueryRunner(Connection con) { this.con = con; } publicT query(String sql, Class type) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException { Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); if (rs.next()) { return toBean(rs, type); } return null; } public List queryList(String sql, Class type) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException { Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); List list = new ArrayList<>(); while (rs.next()) { list.add(toBean(rs, type)); } return list; } private T toBean(ResultSet rs, Class type) throws IntrospectionException, SQLException, InstantiationException, IllegalAccessException { BeanInfo beanInfo = Introspector.getBeanInfo(type); PropertyDescriptor[] props = beanInfo.getPropertyDescriptors(); ResultSetMetaData rsmd = rs.getMetaData(); int[] columnToProperty = mapColumnsToProperties(rsmd, props); return createBean(rs, type, props, columnToProperty); } private T createBean(ResultSet rs, Class type, PropertyDescriptor[] props, int[] columnToProperty) throws SQLException, InstantiationException, IllegalAccessException { T bean = type.newInstance(); for (int i = 1; i < columnToProperty.length; i++) { int propertyIndex = columnToProperty[i]; if (propertyIndex == -1) { continue; } PropertyDescriptor prop = props[propertyIndex]; Class propType = prop.getPropertyType(); Object value = processColumn(rs, i, propType); if (propType != null && value == null && propType.isPrimitive()) { value = primitiveDefaults.get(propType); } callSetter(bean, prop, value); } return bean; } protected int[] mapColumnsToProperties(ResultSetMetaData rsmd, PropertyDescriptor[] props) throws SQLException { int cols = rsmd.getColumnCount(); int[] columnToProperty = new int[cols + 1]; Arrays.fill(columnToProperty, -1); for (int col = 1; col <= cols; col++) { String columnName = rsmd.getColumnName(col); for (int i = 0; i < props.length; i++) { if (columnName.equalsIgnoreCase(props[i].getName())) { columnToProperty[col] = i; break; } } } return columnToProperty; } private Object processColumn(ResultSet rs, int index, Class propType) throws SQLException { if (!propType.isPrimitive() && rs.getObject(index) == null) { return null; } if (propType.equals(String.class)) { return rs.getString(index); } else if (propType.equals(Integer.TYPE) || propType.equals(Integer.class)) { return Integer.valueOf(rs.getInt(index)); } else if (propType.equals(Boolean.TYPE) || propType.equals(Boolean.class)) { return Boolean.valueOf(rs.getBoolean(index)); } else if (propType.equals(Long.TYPE) || propType.equals(Long.class)) { return Long.valueOf(rs.getLong(index)); } else if (propType.equals(Double.TYPE) || propType.equals(Double.class)) { return Double.valueOf(rs.getDouble(index)); } else if (propType.equals(Float.TYPE) || propType.equals(Float.class)) { return Float.valueOf(rs.getFloat(index)); } else if (propType.equals(Short.TYPE) || propType.equals(Short.class)) { return Short.valueOf(rs.getShort(index)); } else if (propType.equals(Byte.TYPE) || propType.equals(Byte.class)) { return Byte.valueOf(rs.getByte(index)); } else if (propType.equals(Timestamp.class)) { return rs.getTimestamp(index); } else { return rs.getObject(index); } } private void callSetter(Object target, PropertyDescriptor prop, Object value) throws SQLException { Method setter = prop.getWriteMethod(); if (setter == null) { return; } Class [] params = setter.getParameterTypes(); try { if (value != null) { if (value instanceof java.util.Date) { if (params[0].getName().equals("java.sql.Date")) { value = new java.sql.Date(((java.util.Date) value).getTime()); } else if (params[0].getName().equals("java.sql.Time")) { value = new java.sql.Time(((java.util.Date) value).getTime()); } else if (params[0].getName().equals("java.sql.Timestamp")) { value = new java.sql.Timestamp(((java.util.Date) value).getTime()); } } } if (isCompatibleType(value, params[0])) { setter.invoke(target, new Object[]{value}); } else { throw new SQLException("Cannot set " + prop.getName() + ": incompatible types."); } } catch (IllegalArgumentException e) { throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage()); } catch (IllegalAccessException e) { throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage()); } catch (InvocationTargetException e) { throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage()); } } private boolean isCompatibleType(Object value, Class type) { if (value == null || type.isInstance(value)) { return true; } else if (type.equals(Integer.TYPE) && Integer.class.isInstance(value)) { return true; } else if (type.equals(Long.TYPE) && Long.class.isInstance(value)) { return true; } else if (type.equals(Double.TYPE) && Double.class.isInstance(value)) { return true; } else if (type.equals(Float.TYPE) && Float.class.isInstance(value)) { return true; } else if (type.equals(Short.TYPE) && Short.class.isInstance(value)) { return true; } else if (type.equals(Byte.TYPE) && Byte.class.isInstance(value)) { return true; } else if (type.equals(Character.TYPE) && Character.class.isInstance(value)) { return true; } else if (type.equals(Boolean.TYPE) && Boolean.class.isInstance(value)) { return true; } return false; } }
为了简化数据库连接的管理,我们开发了一个 DBUtil
工具类:
package com.zzzy.book.manage.util;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public final class DBUtil { private DBUtil() { } public static Connection getConn() { String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"; String user = "root"; String password = "1913599913"; Connection connection = null; try { Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection(url, user, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return connection; } public static void closeConn(Connection conn) { try { if (conn != null && !conn.isClosed()) { conn.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void closeResource(Connection conn, PreparedStatement ps) { try { if (ps != null && !ps.isClosed()) { ps.close(); } if (conn != null && !conn.isClosed()) { conn.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void closeResource(Connection conn, PreparedStatement ps, ResultSet rs) { try { if (ps != null && !ps.isClosed()) { ps.close(); } if (rs != null && !rs.isClosed()) { rs.close(); } if (conn != null && !conn.isClosed()) { conn.close(); } } catch (Exception e) { e.printStackTrace(); } }}
通过 QueryRunner
工具类和 DBUtil
类,开发者可以快速完成数据库操作。以下是一个简单的使用示例:
Connection conn = DBUtil.getConn();Student student = new QueryRunner(conn).query("SELECT id, name, time FROM student WHERE id=1", Student.class);System.out.println(student);
通过以上方法,开发者可以轻松地将 JDBC 返回值映射到对应的 JavaBean 实体类中。 QueryRunner
工具类提供了从数据库到 Java 对象的自动转换功能,使开发过程更加高效和简便。
转载地址:http://pmulz.baihongyu.com/