为什么需要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);
}
}
}