一. DBUtils的引出

1、connection不能提前关闭

当我们查出结果集resultSet的时候,就关闭了connection连接,这时resultSet就不能使用了

示例代码如下:

public class jdbcDBUtils {
    @Test
    public void test() throws Exception{
        Connection connection = JDBCUtils.getConnection();
        String sql = "select * from admin";
        PreparedStatement preStatement = connection.prepareStatement(sql);
        ResultSet resultSet = preStatement.executeQuery();

        /**注意:
         * 以下三种方式,都会导致 java.sql.SQLException: Operation not allowed after ResultSet closed
         * 在使用完resultSet结果集之前,不能将resultSet、preStatement、connection关闭。
         */
        //JDBCUtils.Close(resultSet,null,null);
        //JDBCUtils.Close(null,preStatement,null);
        JDBCUtils.Close(null,null,connection);

        while(resultSet.next()){
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            String pwd = resultSet.getString("pwd");
            System.out.println("id:" + id +" name:" + name + " pwd:" + pwd);
        }
    }
}

运行结果如下:

vip

总结:在使用resultSet结果集之前,不能提前关闭resultSet,preStatement以及connection。

2.resultSet无法重复使用

当遍历完resultSet之后,肯定要关闭连接,导致resultSet无法重复使用。

由1和2引出如下问题:

  ① 如何让resultSet结果集重复使用

  ② 在遍历的过程中,能否简化遍历过程

解决方案:使用DBUtils的jar包

二. DBUtils的使用

1. 在libs中引入dbutils的jar包

2. query语句:

  ① 将表中数据全部查找出来【多行】

public class jdbcDBUtils {
    /**
     * 查询表中所有结果
     * @throws Exception
     */
    @Test
    public void testSearchAll() throws Exception{
        // 1. 在libs中引入dbutils的jar包
        // 2. 获取druid连接池的连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        // 3.使用queryRunner查询结果
        String sql = "select * from admin";
        QueryRunner queryRunner = new QueryRunner();
        // 4.将connection,sql,bean对象,作为参数放入query()中
        //      1)传入连接connection
        //      2)传入sql语句
        //      3)传入bean对象 new BeanListHandler<>(Admin.class) 【反射机制】
        //        resultSet -> admin对象 -> List<Admin>集合
        /** QueryRunner的query()源码如下:
         * 1) public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh) throws SQLException {
         *         return this.query(conn, sql, rsh, (Object[])null);
         *
         * }
         * 注意在 1) 中 调用 2) 时,传入的可变参数是null
         *
         * 2) public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)
         * throws SQLException {
         *         PreparedStatement stmt = null;
         *         ResultSet rs = null;
         *         Object result = null;
         *
         *         try {
         *             // 通过conn和sql创建PreparedStatement类的stmt对象
         *             stmt = this.prepareStatement(conn, sql);
         *             // 将可变参数params传入给sql语句的占位符?
         *             this.fillStatement(stmt, params);
         *             // stmt执行sql语句
         *             rs = this.wrap(stmt.executeQuery());
         *             // 将得到的结果集resultSet--反射机制-->admin对象--封装-->result集合中
         *             result = rsh.handle(rs); // handle()动态绑定机制
         *         } catch (SQLException var33) {
         *             this.rethrow(var33, sql, params);
         *         } finally {
         *             try {
         *                 this.close(rs);
         *             } finally {
         *                 this.close((Statement)stmt);
         *             }
         *         }
         *
         *         // 返回result集合
         *         return result;
         *     }
         */
        List<Admin> query = queryRunner.query(connection,sql, new BeanListHandler<>(Admin.class));
        for (Admin admin : query) {
            System.out.println(admin);
        }
        JDBCUtilsByDruid.Close(null,null,connection);
    }
}

  ①运行结果如下:

Admin{id=3, name='Tom3', pwd='123'}
Admin{id=5, name='Tom2', pwd='123'}
Admin{id=6, name='Tom3', pwd='123'}
Admin{id=8, name='Tom2', pwd='123'}
Admin{id=9, name='Tom3', pwd='123'}
Admin{id=11, name='zw', pwd='123'}
Admin{id=12, name='郑为', pwd='1234'}
Admin{id=13, name='郑威', pwd='1234'}
Admin{id=14, name='郑为', pwd='1234'}
Admin{id=15, name='郑威', pwd='1234'}

Process finished with exit code 0

View Code

  注意①中源码 1) 和 2) 的区别,体现了重载的好处。

  ② 将表中数据按照指定条件筛选出来【单行】

public class jdbcDBUtils {
    /**
     * 查询单行结果
     * @throws Exception
     */
    @Test
    public void testSearchSingle() throws Exception{
        Connection connection = JDBCUtilsByDruid.getConnection();
        QueryRunner queryRunner = new QueryRunner();
        String sql = "select * from admin where id = ?";
        Admin admin = queryRunner.query(connection, sql, new BeanHandler<>(Admin.class),3);
        System.out.println(admin);
        JDBCUtilsByDruid.Close(null,null,connection);
    }
}

  ② 运行结果如下:

Admin{id=3, name='Tom3', pwd='123'}

  ③ 将表中的某一字段按照指定条件筛选出来【单行单列】

public class jdbcDBUtils {
    /**
     * 执行单行单列的查询
     * @throws Exception
     */
    @Test
    public void testSearchScalar() throws Exception{
        Connection connection = JDBCUtilsByDruid.getConnection();
        QueryRunner queryRunner = new QueryRunner();
        String sql = "select name from admin where id = ?";
        Object query = queryRunner.query(connection, sql, new ScalarHandler(), 3);
        System.out.println(query);
        JDBCUtilsByDruid.Close(null,null,connection);
    }
}

  ③ 运行结果如下:

Tom3

①,②,③的区别

① 返回集合,调用的方法:

List<Admin> query = queryRunner.query(connection,sql, new BeanListHandler<>(Admin.class));

  具体运行步骤:resultSet--反射机制--》admin对象--封装--》result集合中。

② 返回对象,调用的方法:

Admin admin = queryRunner.query(connection, sql, new BeanHandler<>(Admin.class),3);

  具体运行步骤:resultSet--反射机制--》admin对象。

③ 返回字段,调用的方法:

Object query = queryRunner.query(connection, sql, new ScalarHandler(), 3);

总结1:

vip

ScalarHandler、BeanHandler、BeanListHandler 都实现了 handle()的方法,①的源码 result = rsh.handle(rs),由动态绑定机制可知,result结果不相同

总结2:

   当需要查出多行数据集时,使用 new BeanListHandler<>(Admin.class) ;

   当需要查出单行数据时,使用 new BeanHandler<>(Admin.class);

   当需要查出单行单例【字段】时,使用 new ScalarHandler()。

3. update语句

public class jdbcDBUtils {
    /**
     * 执行DML语句
     * @throws Exception
     */
    @Test
    public void testDML() throws Exception{
        Connection connection = JDBCUtilsByDruid.getConnection();
        QueryRunner queryRunner = new QueryRunner();
        // 增加insert
        /*
        String insert = "insert into admin values(null,?,?),(null,?,?)";
        int ins = queryRunner.update(connection, insert, "郑为", "1234", "郑威", "1234");
        System.out.println(ins > 0 ? "添加成功":"添加失败");
         */

        // 修改update
        /*
        String update = "update admin set pwd = ? where id = ?";
        int upd = queryRunner.update(connection, update, "123456", 2);
        System.out.println(upd > 0 ? "更新成功":"更新失败");
         */

        // 删除delete
        /*
        String delete = "delete from admin where id = ?";
        queryRunner.update(connection,delete,2);
         */

        // 展现查询结果集,验证是否插入成功
        String sql = "select * from admin";
        // new BeanListHandler<>(Admin.class) 反射机制 result->admin对象->装入list集合
        List<Admin> query1 = queryRunner.query(connection, sql, new BeanListHandler<>(Admin.class));
        for (Admin admin : query1) {
            System.out.println(admin);
        }

        // 查询单行结果,验证是否修改/删除成功
        sql = "select * from admin where id = ?";
        Admin query2 = queryRunner.query(connection, sql, new BeanHandler<>(Admin.class),2);
        System.out.println(query2);

        // 带条件的查询,查询结果
        sql = "select * from admin where name = ?";
        List<Admin> query3 = queryRunner.query(connection, sql, new BeanListHandler<>(Admin.class), "郑为");
        for (Admin admin : query3) {
            System.out.println(admin);
        }
        JDBCUtilsByDruid.Close(null,null,connection);
    }
}

4. 总结

a:使用DBUtils工具类时,无论执行查询语句,还是DML语句,都是由QueryRunner类的对象queryRunner来执行;

b:查询时,queryRunner调用query()方法;修改【增,删,改】时,queryRunner调用update()方法;

c:执行sql语句时,queryRunner(连接名,SQL语句,具体语句具体分析)。

  如果是查询,则是2中①②③的某一类的对象;

  如果是修改,则是3中传入参数。