JDBC和连接池04-210.数据库连接池10.5Apache-DBUtils10.5.1resultSet问题
先分析一个问题
在之前的程序中,执行sql语句后返回的结果集存在如下问题:
关闭connection后,resultSet结果集无法使用
如果要使用结果集,就不能关闭连接,不能关闭连接,就会反过来影响别的程序去连接数据库,就会对多并发程序造成很大的影响
resultSet不利于数据的管理
如果其它的方法或者程序想要使用结果集,也需要一直保持连接,影响其他程序对数据库的连接
使用返回信息也不方便
解决方法:
定义一个类,该类的属性和表的字段是对应关系/映射关系,即用类的属性和表的字段(列)关联起来
我们把这种类叫做JavaBean,或者POJO,Domain。
一个Actor对象就对应一条actor表的记录,将Actor对象放入到ArrayList集合中(将结果集的记录封装到ArrayList中)
10.5.2土方法完成封装
Actor类(JavaBean):
package li.jdbc.datasource;import java.util.Date;/** * Actor对象和actor表的记录对应 */public class Actor {//JavaBean/POJO/Domain private Integer id; private String name; private String sex; private Date borndate; private String phone; public Actor() {//一定要给一个无参构造器[反射需要] } public Actor(Integer id, String name, String sex, Date borndate, String phone) { this.id = id; this.name = name; this.sex = sex; this.borndate = borndate; this.phone = phone; } 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 String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBorndate() { return borndate; } public void setBorndate(Date borndate) { this.borndate = borndate; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @Override public String toString() { return "\nActor{" + "id=" + id + ", name='" + name + '\'' + ", sex='" + sex + '\'' + ", borndate=" + borndate + ", phone='" + phone + '\'' + '}'; }}
测试程序:
package li.jdbc.datasource;import org.junit.Test;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.Date;public class JDBCUtilsByDruid_Use { //使用土方法尝试解决ResultSet问题==封装=>ArrayList @Test public void testSelectToArrayList() {//也可以设置返回值 System.out.println("使用druid方式完成"); //1.得到连接 Connection connection = null; //2.组织一个sql语句 String sql = "Select * from actor where id >=?"; //3.创建PreparedStatement对象 PreparedStatement preparedStatement = null; ResultSet set = null; ArrayList list = new ArrayList();//创建ArrayList对象,存放actor对象 try { connection = JDBCUtilsByDruid.getConnection(); preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1, 1);//给?号赋值 //执行sql,得到结果集 set = preparedStatement.executeQuery(); //遍历该结果集 while (set.next()) { int id = set.getInt("id"); String name = set.getString("name"); String sex = set.getString("sex"); Date borndate = set.getDate("borndate"); String phone = set.getString("phone"); //把得到的当前 resultSet的一条记录,封装到一个Actor对象中,并放入arraylist集合 list.add(new Actor(id,name,sex,borndate,phone)); } System.out.println("list集合数据="+list); //or for (Actor actor:list) { System.out.println("id="+actor.getId()+"\t"+"name="+actor.getName()); } } catch (SQLException e) { e.printStackTrace(); } finally { //关闭资源(不是真的关闭连接,而是将Connection对象放回连接池中) JDBCUtilsByDruid.close(set, preparedStatement, connection); } //因为ArrayList 和 connection 没有任何关联,所以该集合可以复用 //return list; }}
10.5.3Apache-DBUtils
基本介绍
commons-dbutils是Apache组织提供的一个开源 JDBC工具类库,它是对 JDBC的封装,使用dbutils能极大简化 JDBC编码的工作量。
DbUtils类
- QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理
- 使用QueryRunner类实现查询
- ResultSetHandler接口:该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式
方法 | 解释 |
---|---|
ArrayHandler | 将结果集中的第一行数据转成对象数组 |
ArrayListHandler | 把结果集中的每一行数据都转成一个数组,再存放到List中 |
BeanHandler | 将结果集中的第一行数据封装到一个对应的JavaBean实例中 |
BeanListHandler | 将结果集中的每一行数据都封装到一个对应的JavaBean实例中,再存放到List中 |
ColumnListHandler | 将结果集中某一列的数据存放到List中 |
KeyedHandler(name) | 将结果集中的每行数据都封装到Map中,再把这些map再存放到一个map里,其key为指定的key |
MapHandler | 将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值 |
MapListHandler | 将结果集中的每一行数据都封装到一个Map里,然后再存放到List |
DBUtils的jar包下载可以去官网下载
应用实例
使用DBUtils+数据库连接池(德鲁伊)方式,完成对表actor的crud操作
首先将DBUtils的jar包添加到项目的libs文件夹下面,右键选择add as library
Actor类详见10.5.2
DBUtils_USE:
package li.jdbc.datasource;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanListHandler;import org.junit.Test;import java.sql.Connection;import java.sql.SQLException;import java.util.List;public class DBUtils_USE { //使用Apache-DBUtils工具类 + Druid 完成对表的crud操作 @Test public void testQueryMany() throws SQLException {//返回结果是多行多列的情况 //1.得到连接(Druid) Connection connection = JDBCUtilsByDruid.getConnection(); //2.使用DBUtils类和接口(先引入相关的jar,加入到本地的project) //3.创建QueryRunner QueryRunner queryRunner = new QueryRunner(); //4.然后就可以执行相关的方法,返回ArrayList结果集 //String sql = "Select * from actor where id >=?"; //注意 :sql语句也可以查询部分的列,没有查询的属性就在actor对象中置空 String sql = "Select id,name from actor where id >=?"; /** * (1) query方法就是执行sql语句,得到resultSet--封装到-->Arraylist集合中 * (2) 然后返回集合 * (3) connection就是连接 * (4) sql:执行的sql语句 * (5) new BeanListHandler(Actor.class): 将resultSet->Actor对象->封装到ArrayList * 底层使用反射机制,去获取 Actor的属性,然后进行封装 * (6) 1 就是给sql语句中的?赋值,可以有多个值,因为是可变参数 * (7) 底层得到的resultSet,会在query关闭,同时也会关闭PreparedStatement对象 */ List list = queryRunner.query(connection, sql, new BeanListHandler(Actor.class), 1); System.out.println("输出集合的信息:"); for (Actor actor : list) { System.out.print(actor); } //释放资源 JDBCUtilsByDruid.close(null, null, connection); }}
10.5.4ApDBUtils源码分析
在上述10.5.3代码中,在List list = queryRunner.query(connection, sql, new BeanListHandler(Actor.class), 1);
语句旁打上断点,点击debug,点击step into
光标跳转到如下方法:
public T query(Connection conn, String sql, ResultSetHandler rsh, Object... params) throws SQLException { PreparedStatement stmt = null;//定义PreparedStatement对象 ResultSet rs = null;//接收返回的resultSet T result = null;//返回ArrayList try { stmt = this.prepareStatement(conn, sql);//创建PreparedStatement this.fillStatement(stmt, params);//对SQL语句进行?赋值 rs = this.wrap(stmt.executeQuery());//执行SQL,返回resultSet result = rsh.handle(rs);//将返回的resultSet-->封装到ArrayList中[使用反射,对传入的class对象进行处理] } catch (SQLException e) { this.rethrow(e, sql, params); } finally { try { close(rs);//关闭resultSet } finally { close(stmt);//关闭preparedStatement } } return result;//返回ArrayList}
10.5.5ApDBUtils查询
使用DBUtils+数据库连接池(德鲁伊)方式,完成对表actor的查询操作
1.多行多列
package li.jdbc.datasource;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanListHandler;import org.junit.Test;import java.sql.Connection;import java.sql.SQLException;import java.util.List;public class DBUtils_USE { //返回结果是多行多列的情况 @Test public void testQueryMany() throws SQLException { //得到连接(Druid) Connection connection = JDBCUtilsByDruid.getConnection(); //创建QueryRunner QueryRunner queryRunner = new QueryRunner(); //然后就可以执行相关的方法,返回ArrayList结果集 //sql语句也可以查询部分的列,没有查询的属性就在actor对象中置空 String sql = "Select id,name from actor where id >=?"; List list = queryRunner.query(connection, sql, new BeanListHandler(Actor.class), 1); System.out.println("输出集合的信息:"); for (Actor actor : list) { System.out.print(actor); } //释放资源 JDBCUtilsByDruid.close(null, null, connection); }}
2.单行多列
package li.jdbc.datasource;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanHandler;import org.junit.Test;import java.sql.Connection;public class DBUtils_USE { //演示DBUtils+druid完成-返回的结果是单行记录(单个对象)的情况-单行多列 @Test public void testQuerySingle() throws Exception { //1.得到连接 Connection connection = JDBCUtilsByDruid.getConnection(); //2.创建QueryRunner对象 QueryRunner queryRunner = new QueryRunner(); //3.执行相关方法,返回单个对象 String sql = "Select * from actor where id =?"; //因为我们返回的是单行记录,对应单个对象, // 因此使用的 Handler是BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中 Actor actor = queryRunner.query(connection, sql, new BeanHandler(Actor.class), 2); System.out.println(actor); //释放资源 JDBCUtilsByDruid.close(null, null, connection); }}
3.单行单列
package li.jdbc.datasource;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.ScalarHandler;import org.junit.Test;import java.sql.Connection;public class DBUtils_USE { //演示DBUtils+druid完成-查询结果是单行单列的情况-返回的就是Object @Test public void testScalar() throws Exception {//Scalar 单一值 //获取连接 Connection connection = JDBCUtilsByDruid.getConnection(); //创建QueryRunner对象 QueryRunner queryRunner = new QueryRunner(); //执行相关方法,返回单行单列 String sql = "Select name from actor where id =?"; //因为返回的是一个对象,因此使用的 Handler是 ScalarHandler Object obj = queryRunner.query(connection, sql, new ScalarHandler(), 1); System.out.println(obj); //释放资源 JDBCUtilsByDruid.close(null,null,connection); }}
10.5.6ApDBUtilsDML
使用DBUtils+数据库连接池(德鲁伊)方式,完成对表actor的DML(update,insert,delete)操作
package li.jdbc.datasource;import org.apache.commons.dbutils.QueryRunner;import org.junit.Test;import java.sql.Connection;import java.sql.SQLException;public class DBUtils_USE { //演示DBUtils+druid完成 dml操作 @Test public void testDML() throws SQLException { //获取连接 Connection connection = JDBCUtilsByDruid.getConnection(); //创建QueryRunner对象 QueryRunner queryRunner = new QueryRunner(); //这里组织sql完成update,insert,delete //String sql = "update actor set name =? where id =?"; //String sql = "insert into actor values (null,?,?,?,?)"; String sql = "delete from actor where id =?"; /** * 1.执行dml的操作是queryRunner.update() * 2.返回的值是受影响的行数,如果返回的是0,代表sql执行失败 或者 执行成功但是表没受影响 */ //int affectedRow = queryRunner.update(connection, sql,"黎明","女","1999-10-09","123"); int affectedRow = queryRunner.update(connection, sql,1000); System.out.println(affectedRow > 0 ? "执行成功" : "执行没有影响到表"); //释放资源 JDBCUtilsByDruid.close(null, null, connection); }}
10.6表和JavaBean的类型映射关系