Apache DBUtils

为什么需要DBUtils:关闭connection后resultSet结果集无法使用,且resultSet结果集不方便使用
commons-dbutils是Apache提供的一个开源JDBC工具类库,他是对JDBC的封装使用DBUtil能极大简化JDBC编码工作量
1.QueryRunner类:封装了SQL的执行,是线程安全的,可是实现CRUD、批处理

QueryRunner queryRunner = QueryRunner(DataSource ds)
打开一个连接->执行查询sql->使用ResultSetHandler处理返回结果集->关闭连接
QueryRunner是自动打开/关闭连接的,自然会影响到事务控制相关的功能
比较适合执行select语句,不适合insert/update/delete

QueryRunner queryRunner = new QueryRunner();//需要自己控制连接,适合需要事务控制语句执行

QueryRunner中提供对sql语句的操作:
(1).query()用于执行select操作
(2).update()用于执行更新操作(insert、update、delete)
(3).batch()批处理

2.ResultSetHandler接口:将java.sql.ResultSet数据按要求转换为另一种数据形式
共有13个实现子类:常用子类如下
★★BeanListHandler:将查询结果的每一条记录封装成指定的bean对象,将每一个bean对象放入list中返回
★★BeanHandler:将查询结果的第一条记录封装成指定的bean对象返回
★MapListHandler:将查询结果的每一条记录封装map集合,将每一个map集合放入list中返回
★ScalarHandler:取单行单列数据(一个单元格)

3.测试
(1)pom引入
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.7</version>
</dependency>

//Student实体类
@Data
public class Student {
    private int id;
    private String name;
}

@Test
public void test1() throws SQLException {
    //传入一个dataSource,方法里面自动打开连接和关闭连接,适合不需要事务控制的SQL执行
    QueryRunner queryRunner = new QueryRunner(C3P0Util.dataSource);
    List<Student> list = queryRunner.query("SELECT * FROM student", new BeanListHandler<>(Student.class));
    list.forEach(e -> System.out.print(e));
}

@Test
public void test2() throws SQLException {
    Connection connection = null;
    try {
        //由自己控制连接的打开/关闭,有利于对事务控制,调用方法时需要传入connection
        connection = C3P0Util.getConnection();
        connection.setAutoCommit(false);//开启事务
        QueryRunner queryRunner = new QueryRunner();
        List<Student> list = queryRunner.query(connection, "SELECT * FROM student", new BeanListHandler<>(Student.class));
        list.forEach(e -> System.out.print(e));
        int insertCount = queryRunner.update(connection, "INSERT INTO student VALUES( ?, ?)", 5001, "李四");
        System.out.println("insert条数:" + insertCount);
        int updateCount = queryRunner.update(connection, "UPDATE student SET name = ? WHERE id = ?", "张三", 5001);
        System.out.println("update条数:" + updateCount);
        int deleteCount = queryRunner.update(connection, "DELETE FROM student WHERE id = ?", 5001);
        System.out.println("delete条数:" + deleteCount);
        Object[][] params = new Object[10][];
        for (int i = 0; i < 10; i++) {
            params[i] = new Object[]{"student" + i};
        }
        int[] batch = queryRunner.batch(connection, "INSERT INTO student VALUES (null, ?)", params);
        //所有CURD、批量执行完毕后,提交事务
        connection.commit();
        //关闭连接
        C3P0Util.close(null, null, connection);
    } catch (SQLException e) {
        connection.rollback();
        throw new RuntimeException(e);
    }
}

@Test
public void test3() throws SQLException {
    QueryRunner queryRunner = new QueryRunner(DruidUtil.dataSource);
    //将查询结果的每一条记录封装成指定的bean对象,将每一个bean对象放入list中返回
    List<Student> list = queryRunner.query("SELECT * FROM student", new BeanListHandler<>(Student.class));
    list.forEach(e -> System.out.println(e));
    //将查询结果的第一条记录封装成指定的bean对象返回
    Student student = queryRunner.query("SELECT * FROM student WHERE id = 5002", new BeanHandler<>(Student.class));
    System.out.println("一条记录student=" + student);
    //将查询结果的每一条记录封装map集合,将每一个map集合放入list中返回
    List<Map<String, Object>> list2 = queryRunner.query("SELECT * FROM student", new MapListHandler());
    for (Map<String, Object> map : list2) {
        for (Map.Entry<String, Object> m : map.entrySet()) {
            System.out.println(m.getKey() + "\t" + m.getValue());
        }
        System.out.println("------------------------------");
    }
    //取单行单列数据(一个单元格)
    Object count = queryRunner.query("SELECT COUNT(*) FROM student", new ScalarHandler());
    System.out.println("一个单元格count=" + count);
    Object name = queryRunner.query("SELECT name FROM student WHERE id = 5002", new ScalarHandler());
    System.out.println("一个单元格name=" + name);
}

4.源码分析
//由QueryRunner创建Connection,boolean closeConn = true
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
    Connection conn = this.prepareConnection();
    return this.query(conn, true, sql, rsh, params);
}
//自己传入Connection,boolean closeConn = false
public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh) throws SQLException {
    return this.query(conn, false, sql, rsh, (Object[])null);
}

//都调用此方法
private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {

PreparedStatement stmt = null;
ResultSet rs = null;
//查询的结果集
Object result = null;
//返回的数据

try {
    stmt = this.prepareStatement(conn, sql);//创建PreparedStatement
    this.fillStatement(stmt, params);//对SQL进行?赋值
    rs = this.wrap(stmt.executeQuery());执行SQL语句返回ResultSet
    result = rsh.handle(rs);//ResultSetHandler转换数据

//ResultSet、PreparedStatement调用query后关闭,根据closeConn选择关闭Connection 
finally {
    try {
        this.close(rs);
    } finally {
        this.close(stmt);
        if (closeConn) {
            this.close(conn);
        }
    }
}
上一篇:类和对象:给大家介绍对象 - 零基础入门学习Python036


下一篇:JDBC:DBUtils工具类 - 介绍