zoukankan      html  css  js  c++  java
  • JDBC学习笔记(9)——DBUtils的使用

    使用DBUtils提供的功能需要使用commons-dbutils-1.6.jar这个JAR包,在Apache官网可以下载到

    使用DBUtils进行更新操

    测试QueryRunner类的update方法 ,该方法可用于insert,update,delete操作
    具体代码实现

     1     @Test
     2     public void testQuertRunnerUpdate() {
     3         // 1.创建QueryRunner的实现类
     4         String sql = "delete from customers" + " where id in (?,?)";
     5         Connection connection = null;
     6         try {
     7             connection = JDBCTools.getConnection();
     8             queryRunner.update(connection, sql, 3, 4);
     9 
    10         } catch (Exception e) {
    11             e.printStackTrace();
    12         } finally {
    13             JDBCTools.release(null, null, connection);
    14         }
    15     }

    我们可以查看一下update方法的源码,可以看到是调用的是重载形式的update:

    conn:数据库连接

    sql:SQL语句

    params:填充占位符的参数

    1  public int update(Connection conn, String sql, Object... params) throws SQLException {
    2         return update(conn, false, sql, params);
    3     }

    看具体实现代码:

     1     private int update(Connection conn, boolean closeConn, String sql, Object... params) throws SQLException {
     2         if (conn == null) {
     3             throw new SQLException("Null connection");
     4         }
     5 
     6         if (sql == null) {
     7             if (closeConn) {
     8                 close(conn);
     9             }
    10             throw new SQLException("Null SQL statement");
    11         }
    12         //封装使用的是PreparedStatement
    13         PreparedStatement stmt = null;
    14         int rows = 0;
    15 
    16         try {
    17             stmt = this.prepareStatement(conn, sql);
               //填充占位符的操作
    18             this.fillStatement(stmt, params);
               //执行更新操作
    19             rows = stmt.executeUpdate();
    20 
    21         } catch (SQLException e) {
    22             this.rethrow(e, sql, params);
    23 
    24         } finally {
    25             close(stmt);
    26             if (closeConn) {
    27                 close(conn);
    28             }
    29         }
    30 
    31         return rows;
    32     }

    可以看到QueryRunner中封装的都是我们所熟悉的基本操作,测试我们的testQuertRunnerUpdate方法,可以发现对应id为3,4的记录已经被删除

    测试QueryRunner的查询方法query

     1 // 因为是线程安全的,所以queryRunner可以放到这个位置
     2     QueryRunner queryRunner = new QueryRunner();
     3 
     4     class MyResultSetHandler implements ResultSetHandler {
     5 
     6         @Override
     7         public Object handle(ResultSet resultSet) throws SQLException {
     8             List<Customer> customers = new ArrayList<Customer>();
     9             while (resultSet.next()) {
    10                 int id = resultSet.getInt(1);
    11                 String name = resultSet.getString(2);
    12                 String email = resultSet.getString(3);
    13                 Date birth = resultSet.getDate(4);
    14                 Customer customer = new Customer(id, name, email, birth);
    15                 customers.add(customer);
    16             }
    17             return customers;
    18         }
    19 
    20     }
    21 
    22     @Test
    23     public void testQuery() {
    24         QueryRunner queryRunner = new QueryRunner();
    25         Connection connection = null;
    26         try {
    27             connection = JDBCTools.getConnection();
    28             String sql = "select id,name,email,birth" + " from customers";
    29             Object obj = queryRunner.query(connection, sql,
    30                     new MyResultSetHandler());
    31             System.out.println(obj);
    32         } catch (Exception e) {
    33             e.printStackTrace();
    34         } finally {
    35             JDBCTools.release(null, null, connection);
    36         }
    37     }

    运行方法可以看到我们要查询的结果:

    [Customer [id=1, name=ATGUIGU, email=simale@163.com, birth=2016-05-08], Customer [id=2, name=ABCDE, email=abcd@guigu.com, birth=2016-05-08], Customer [id=5, name=dsv, email=474405914@qq.com, birth=2016-05-10]]

    我们查看一下query方法的源码

     1 private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params)
     2             throws SQLException {
     3         if (conn == null) {
     4             throw new SQLException("Null connection");
     5         }
     6 
     7         if (sql == null) {
     8             if (closeConn) {
     9                 close(conn);
    10             }
    11             throw new SQLException("Null SQL statement");
    12         }
    13 
    14         if (rsh == null) {
    15             if (closeConn) {
    16                 close(conn);
    17             }
    18             throw new SQLException("Null ResultSetHandler");
    19         }
    20 
    21         PreparedStatement stmt = null;
    22         ResultSet rs = null;
    23         T result = null;
    24 
    25         try {
    26             stmt = this.prepareStatement(conn, sql);
    27             this.fillStatement(stmt, params);
    28             rs = this.wrap(stmt.executeQuery());
    29             result = rsh.handle(rs);
    30 
    31         } catch (SQLException e) {
    32             this.rethrow(e, sql, params);
    33 
    34         } finally {
    35             try {
    36                 close(rs);
    37             } finally {
    38                 close(stmt);
    39                 if (closeConn) {
    40                     close(conn);
    41                 }
    42             }
    43         }
    44 
    45         return result;
    46     }

    其中最关键的是这四个语句:

                stmt = this.prepareStatement(conn, sql);
                this.fillStatement(stmt, params);
                rs = this.wrap(stmt.executeQuery());
                result = rsh.handle(rs);
    测试DBUtils工具类 QueryRunner:
     * query(Connection conn,String sql,ResultSetHandler rsh){ 
     * 这三个步骤就是为了得到结果集 
     * stmt = this.prepareStatement(conn, sql);
     * this.fillStatement(stmt, params);
     * rs = this.wrap(stmt.executeQuery());
     * 调用传入的ResultSetHandler对象的handle方法,并且把前面得到的ResultSet对象作为参数传入
     * result =rsh.handle(rs); 
     * 把result作为结果返回 
     * return result
     * }

    测试BeanHandler的用法
    BeanHandler:把结果集的第一条记录转为创建BeanHandler 对象时传入的Class参数对应的对象。

    具体测试代码:

     1 public void testBeanHandler() {
     2         Connection connection = null;
     3         try {
     4             connection = JDBCTools.getConnection();
     5             String sql = "select id,name,email,birth"
     6                     + " from customers where id=?";
     7             Customer customer = queryRunner.query(connection, sql,
     8                     new BeanHandler(Customer.class), 5);
     9             System.out.println(customer);
    10         } catch (Exception e) {
    11             e.printStackTrace();
    12         } finally {
    13             JDBCTools.release(null, null, connection);
    14         }
    15     }

    查看源码可以看到query函数中用到的handler函数实现的功能是这样的

    1   @Override
    2     public T handle(ResultSet rs) throws SQLException {
    3         return rs.next() ? this.convert.toBean(rs, this.type) : null;
    4     }

    实现的功能是把结果集的第一条记录转为创建BeanHandler 对象时传入的Class参数对应的对象。

    其中的toBean方法的实现方式:(多看源码吧,有点乱了)

        public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException {
    
            PropertyDescriptor[] props = this.propertyDescriptors(type);
    
            ResultSetMetaData rsmd = rs.getMetaData();
            int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
    
            return this.createBean(rs, type, props, columnToProperty);
        }

    测试BeanListHandler的用法
    和前面那个差不多,只不过将查询的结果放到了一个List容器中了

     1     @Test
     2     public void testBeanListHandler() {
     3         Connection connection = null;
     4         try {
     5             connection = JDBCTools.getConnection();
     6             String sql = "select id,name,email,birth" + " from customers";
     7             List<Customer> customers = queryRunner.query(connection, sql,
     8                     new BeanListHandler(Customer.class));
     9             System.out.println(customers);
    10         } catch (Exception e) {
    11             e.printStackTrace();
    12         } finally {
    13             JDBCTools.release(null, null, connection);
    14         }
    15     }

    运行结果:

    [Customer [id=1, name=ATGUIGU, email=simale@163.com, birth=2016-05-08], Customer [id=2, name=ABCDE, email=abcd@guigu.com, birth=2016-05-08], Customer [id=5, name=dsv, email=474405914@qq.com, birth=2016-05-10]]

    测试MapHandler的用法

    MapHandler:返回SQL对应的第一条记录对应的Map对象 键:SQL查询的列名(不是列别名) 值:列的值

     1 @Test
     2     public void testMapHandler() {
     3         Connection connection = null;
     4         try {
     5             connection = JDBCTools.getConnection();
     6             String sql = "select id,name,email,birth" + " from customers";
     7             Map<String, Object> result = queryRunner.query(connection, sql,
     8                     new MapHandler());
     9             System.out.println(result);
    10         } catch (Exception e) {
    11             e.printStackTrace();
    12         } finally {
    13             JDBCTools.release(null, null, connection);
    14         }
    15     }

    运行结果:

    {id=1, name=ATGUIGU, email=simale@163.com, birth=2016-05-08}

    测试MapListHandler的用法

    MapListHandler:将结果集转为一个Map的List, Map对应查询的一条记录的Map对象

    键:SQL查询的列名(不是列别名)
    值:列的值 而MapListHandler:返回的多条记录对应的Map集合

     1 @Test
     2     public void testMapListHandler() {
     3         Connection connection = null;
     4         try {
     5             connection = JDBCTools.getConnection();
     6             String sql = "select id,name,email,birth" + " from customers";
     7             List<Map<String, Object>> result = queryRunner.query(connection,
     8                     sql, new MapListHandler());
     9             System.out.println(result);
    10         } catch (Exception e) {
    11             e.printStackTrace();
    12         } finally {
    13             JDBCTools.release(null, null, connection);
    14         }
    15     }

    运行结果:

    [{id=1, name=ATGUIGU, email=simale@163.com, birth=2016-05-08}, {id=2, name=ABCDE, email=abcd@guigu.com, birth=2016-05-08}, {id=5, name=dsv, email=474405914@qq.com, birth=2016-05-10}]

    测试ScalarHandler的用法

    ScalarHandle:把结果集转为一个数值(可以是任意基本数据类型和字符串,Date等)返回

     1 @Test
     2     public void testScalarHandler() {
     3         Connection connection = null;
     4         try {
     5             connection = JDBCTools.getConnection();
     6             String sql = "select count(id) from customers";
     7             Object result = queryRunner.query(connection, sql,
     8                     new ScalarHandler());
     9             System.out.println(result);
    10         } catch (Exception e) {
    11             e.printStackTrace();
    12         } finally {
    13             JDBCTools.release(null, null, connection);
    14         }
    15     }

    运行结果:3

    至此为止我们学习了JDBC中常用的一些知识点,下面我们就使用DBUtils编写通用的DAO(DAO其实就是封装了操作数据库数据的一些方法的接口)

    使用DButils编写通用的DAO

    第一步:先写一个访问数据的DAO接口

     1 package com.atguigu.jdbc;
     2 
     3 import java.sql.Connection;
     4 import java.util.List;
     5 
     6 /**
     7  * 访问数据的DAO接口
     8  * 里面定义好访问数据表的各种方法
     9  * @author Administrator
    10  * @param T:DAO处理的实体类的类型
    11  */
    12 public interface DAO {
    13     /**
    14      * 批量处理的方法
    15      * @param connection
    16      * @param sql
    17      * @param args:填充占位符的Object[]类型的可变参数
    18      */
    19     void batch(Connection connection,
    20     String sql,Object[] ...args);
    21     /**
    22      * 返回一个具体的一个值,例如总人数,平均工资
    23      * 某一个认得email
    24      * @param connection
    25      * @param sql
    26      * @param args
    27      * @return
    28      */
    29     <E> E getForValue(Connection connection,
    30     String sql,    Object ...args);
    31     
    32     /**
    33      * 返回T的一个集合
    34      * @param <T>
    35      * @param connection
    36      * @param sql
    37      * @param args
    38      * @return
    39      */
    40     <T> List<T> getForList(Connection connection,
    41     String sql,Object ...args);
    42     /**
    43      * 返回一个T的对象
    44      * @param <T>
    45      * @param connection
    46      * @param sql
    47      * @param args 
    48      * @return
    49      * @throws Exception 
    50      */
    51     <T> T get(Connection connection,String sql,Object ...args) throws Exception;
    52     /**
    53      * 
    54      * @param connection:数据库连接
    55      * @param sql:SQL语句
    56      * @param args:填充占位符的可变参数
    57      */
    58     void update(Connection connection,String sql,Object ...args);
    59 }
    View Code

    第二步:定义实现该接口的实例类JdbcDAOImpl

     1 package com.atguigu.jdbc;
     2 
     3 import java.sql.Connection;
     4 import java.util.List;
     5 
     6 import org.apache.commons.dbutils.QueryRunner;
     7 import org.apache.commons.dbutils.handlers.BeanHandler;
     8 
     9 /**
    10  * 使用QueryRunner提供其具体的实现
    11  * @author Administrator
    12  *
    13  * @param <T>:子类需传入的泛型类型
    14  */
    15 public class JdbcDAOImpl<T> implements DAO {
    16     private QueryRunner queryRunner=null;
    17     private Class<T> type; 
    18     public  JdbcDAOImpl() {
    19         queryRunner=new QueryRunner();
    20         type= (Class<T>) ReflectionUtils.getGenericSuperClass(getClass(),0);
    21     }
    22     @Override
    23     public void batch(Connection connection, String sql, Object[]... args) {
    24     }
    25 
    26     @Override
    27     public <E> E getForValue(Connection connection, String sql, Object... args) {
    28         
    29         return null;
    30     }
    31 
    32     @Override
    33     public  List<T> getForList(Connection connection, String sql,
    34             Object... args) {
    35         
    36         return null;
    37     }
    38 
    39     @Override
    40     public  T get(Connection connection, String sql, Object... args) throws Exception {
    41         
    42         return  queryRunner.query(connection, sql,
    43         new BeanHandler<>(type),args);
    44     }
    45 
    46     @Override
    47     public void update(Connection connection, String sql, Object... args) {
    48     }
    49 
    50     
    51 }
    View Code

    第三步:定义一个具体操作的类继承自JdbcDAOImpl

    1 package com.atguigu.jdbc;
    2 
    3 public class CustomerDAO extends JdbcDAOImpl<Customer>{
    4     
    5 }

    第四步:我们测试一下我们已经实现的get方法,其他的方法实现过程类似

     1 package com.atguigu.jdbc;
     2 
     3 import static org.junit.Assert.*;
     4 
     5 import java.sql.Connection;
     6 
     7 import org.junit.Test;
     8 
     9 public class CustomerDaoTest {
    10     CustomerDAO customerDAO=new CustomerDAO();
    11 
    12     @Test
    13     public void testBatch() {
    14         fail("Not yet implemented");
    15     }
    16 
    17     @Test
    18     public void testGetForValue() {
    19         fail("Not yet implemented");
    20     }
    21 
    22     @Test
    23     public void testGetForList() {
    24         fail("Not yet implemented");
    25     }
    26 
    27     @Test
    28     public void testGet() {
    29         Connection connection=null;
    30         try {
    31             connection=JDBCTools.getConnection();
    32             String sql = "select id,name,email,birth"
    33                     + " from customers where id=?";
    34             Customer customer=customerDAO.get(connection, sql, 5);
    35             System.out.println(customer);
    36         } catch (Exception e) {
    37             e.printStackTrace();
    38         }finally{
    39             JDBCTools.release(null, null, connection);
    40         }
    41     }
    42 
    43     @Test
    44     public void testUpdate() {
    45         fail("Not yet implemented");
    46     }
    47 
    48 }
    View Code

    运行一下:

    Customer [id=5, name=dsv, email=474405914@qq.com, birth=2016-05-10]

    可以通过我们的get方法得到我们想要的数据信息


    个人感悟:把简单的事情做到极致,打扎实的基础,写优秀的代码

    本文为博主原创文章,转载请注明出处:http://www.cnblogs.com/ysw-go/
    1、本博客的原创原创文章,都是本人平时学习所做的笔记,如有错误,欢迎指正。
    2、如有侵犯您的知识产权和版权问题,请通知本人,本人会即时做出处理文章。
    3、本博客的目的是知识交流所用,转载自其它博客或网站,作为自己的参考资料的,感谢这些文章的原创人员

  • 相关阅读:
    typeof 和 Object.prototype.toString 的区别
    获取地理信息的JavaScript 库 -- YQL Geo
    关于html5手机
    我看过的书的示例网站
    解决跨浏览器问题网站收集
    【docker】docker初试与填坑
    sunJCE or ibmJce,was服务器下使用des的注意点
    cxf-webservice-在was6服务器上运行
    微星b85(b85i b85-gaming) 系列dsdt
    IE10的bug?disabled button如何触发事件
  • 原文地址:https://www.cnblogs.com/ysw-go/p/5478503.html
Copyright © 2011-2022 走看看