写在前面

在阅读本文之前,你或许应该先了解:

  • JDBC的实现步骤(注册驱动、建立连接、发送SQL、处理结果集)
  • 数据库连接池的使用(本文使用c3p0连接池)

DbUtils是Apache的一个对于数据库操作的封装类,本文重写了DbUtils的query与update方法,而代码着重于封装的实现原理,对于很多异常等都未做详细的处理。

实现步骤

  1. 首先,通过c3p0连接池建立数据库连接,并获取连接对象。
  • 导入c3p0-0.9.2-pre1.jar
  • 创建c3p0.propertiesc3p0-config.xml文件,下面是.xml文件主要内容:
<?xml version="1.0" encoding="UTF-8"?>  
<c3p0-config>  
 <!-- 默认配置,当使用ComboPooledDataSource无参构造器时,使用的就是这个配置 -->  
 <default-config>  
 <!-- 基本配置 -->  
 <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/share?serverTimezone=Asia/Shanghai&amp;useSSL=false&amp;characterEncoding=utf8</property>  
 <property name="driverClass">com.mysql.cj.jdbc.Driver</property>  
 <property name="user">root</property>  
 <property name="password">123456</property>  
 <!-- 每次增量,当需要创建Connection对象时,一次创建几个 -->  
 <property name="acquireIncrement">3</property>  
 <!-- 当创建池对象后,池中应该有几个Connection对象 -->  
 <property name="initialPoolSize">10</property>  
 <!-- 池中最少Connection个数,如果少于这个值,就会创建Connection -->  
 <property name="minPoolSize">2</property>  
 <!-- 池中最大连接个数 -->  
 <property name="maxPoolSize">15</property>  
 </default-config>
</c3p0-config> 
  • 创建数据库连接池,获取连接对象的包装类JdbcUtil
public class JdbcUtil {  
    private static ComboPooledDataSource dataSource = new ComboPooledDataSource();  
  
 public static Connection getConnection(){  
        Connection conn = null;  
 try {  
            conn = dataSource.getConnection();  
 } catch (SQLException e) {  
            e.printStackTrace();  
 }  
        return conn;  
 }  
  
    public static DataSource getDataSource(){  
        return dataSource;  
 }  
}
  1. 数据库增删查改的类MyRunner
public class MyRunner {  
    private DataSource dataSource;  
  
 public MyRunner(DataSource dataSource){  
        this.dataSource = dataSource;  
 }  
  
    public <T> T query(String sql, MyResultSetHandler<T> handler, Object... params){  
        T result = null;  
 try {  
            Connection conn = dataSource.getConnection();  
 PreparedStatement pstmt = conn.prepareStatement(sql);  
 generateParams(pstmt, params); // 给pstmt赋值  
 result = handler.handle(pstmt.executeQuery());  
 } catch (SQLException e) {  
            e.printStackTrace();  
 }  
        return result;  
 }  
  
    /**  
 * 数据操作 包括增、删、改  
 * @param sql sql语句  
 * @param params 参数列表  
 */  
 public void update(String sql, Object... params){  
        try {  
            Connection conn = dataSource.getConnection();  
 PreparedStatement pstmt = conn.prepareStatement(sql);  
 generateParams(pstmt, params); // 给pstmt赋值  
 pstmt.executeUpdate();  
 } catch (SQLException e) {  
            e.printStackTrace();  
 }  
    }  
  
    /**  
 * 给指定的pstmt 预处理的? 赋值  
 * @param pstmt PreparedStatement  
 * @param params 参数列表  
 * @throws SQLException  
 */ private static void generateParams(PreparedStatement pstmt, Object[] params) throws SQLException {  
        for(int i = 1; i <= params.length; i++){  
            pstmt.setObject(i, params[i-1]);  
 }  
    }  
}
  1. 创建统一的处理ResultSet结果集的接口类MyResultSetHandler
/**  
 * @Auther dbc  
 * @Date 2020/9/11 17:04  
 */
public interface MyResultSetHandler<T> {  
    T handle(ResultSet resultSet) throws SQLException;  
}
  1. 实现上一步的接口MyBeanHandler
public class MyBeanHandler<T> implements MyResultSetHandler<T> {  
  
    private Class<T> clazz;  
  
 public MyBeanHandler(Class<T> T){  
        this.clazz = T;  
 }  
  
  
    @Override  
 public T handle(ResultSet resultSet) throws SQLException {  
        T t = null;  
 if(resultSet.next()){  
            try {  
                t = clazz.newInstance();  
 ResultSetMetaData metaData = resultSet.getMetaData();  
 int columnCount = metaData.getColumnCount();  
 for(int i = 1; i <= columnCount; i++){  
                    String columnName = metaData.getColumnName(i);  
 Object columnValue = resultSet.getObject(columnName);  
 try {  
                        Field field = clazz.getDeclaredField(columnName);  
 field.setAccessible(true); // 获取访问操作权限  
 field.set(t, columnValue);  
 }catch (NoSuchFieldException e){  
                        e.printStackTrace();  
 }  
                }  
            } catch (InstantiationException | IllegalAccessException e) {  
                e.printStackTrace();  
 }  
        }  
        return t;  
 }  
  
}
  1. 对于结果集为多个,需要用List来接收,同样用一个类来实现MyResultSetHandler,传入List<T>即可,本文就不再做演示。
  2. 增加测试类Account,数据库也应当存在此表即一些测试数据。主要有以下字段:
private int id;  
private String name;  
private Double money;
//注意:mysql中定义decimal字段,应由BigDecimal来接收
  1. 测试
public static void main(String[] args)  {  
    MyRunner myRunner= new MyRunner(JdbcUtil.getDataSource());  
 Account account = myRunner.query("SELECT * FROM account WHERE id =?;",new MyBeanHandler<Account>(Account.class),1);  
 System.out.println(account);  
 List<Account> accounts = myRunner.query("SELECT * FROM account",new MyBeanListHandler<>(Account.class));  
 System.out.println(accounts);  
}

邓奔成
6 声望4 粉丝

下一篇 »
有效的数独