JDBC和连接池04-210.数据库连接池10.5Apache-DBUtils10.5.1resultSet问题

先分析一个问题

在之前的程序中,执行sql语句后返回的结果集存在如下问题:

  1. 关闭connection后,resultSet结果集无法使用

    如果要使用结果集,就不能关闭连接,不能关闭连接,就会反过来影响别的程序去连接数据库,就会对多并发程序造成很大的影响

  2. resultSet不利于数据的管理

    如果其它的方法或者程序想要使用结果集,也需要一直保持连接,影响其他程序对数据库的连接

  3. 使用返回信息也不方便

解决方法:

定义一个类,该类的属性和表的字段是对应关系/映射关系,即用类的属性和表的字段(列)关联起来
我们把这种类叫做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类

  1. QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理
  2. 使用QueryRunner类实现查询
  3. 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的类型映射关系