• JDBC07-----代码重构之封装DBCUtils工具类


    一. 代码重构原则

    之前的DAO操作,除了sql语句和set值不一样,其它都一样,有太多的重复代码。因此需要重构。

    重构代码原则:

    二. 抽取DML方法

    1. 具体抽取成executeUpdate方法在每一个dao实现中

     1 /**
     2      * 重构DML操作
     3      */
     4     public int executeUpdate(String sql,Object...params) {
     5         Connection connection=null;
     6         PreparedStatement pStatement=null;
     7         
     8         try {
     9             //1.加载驱动
    10             //2.连接数据库
    11             connection=JDBCUtil.getConnection();
    12             //3.创建语句
    13             pStatement=connection.prepareStatement(sql);
    14             //4.遍历参数
    15             for(int i=0;i<params.length;i++) {
    16                 pStatement.setObject(i+1, params[i]);
    17             }
    18             //4.执行语句
    19             return pStatement.executeUpdate();
    20         } catch (SQLException e) {
    21             // TODO Auto-generated catch block
    22             e.printStackTrace();
    23         }finally {
    24             JDBCUtil.close(connection, pStatement, null);
    25         }
    26         return 0;
    27     }
    28 
    29     public void save(Stu stu) {
    30         String sql="insert into stu(name,age) values(?,?)";
    31         this.executeUpdate(sql,stu.getName(),stu.getAge());
    32     }
    View Code

    测试:

    1 @Test
    2     public void testSave() {
    3         IStuDao dao=new StuDaoImpl();
    4         Stu stu=new Stu();
    5         stu.setName("hehe");
    6         stu.setAge(23);
    7         dao.save(stu);
    8     }
    View Code

    这样可以成功,但是倘若每个dao的实现类里面都写这个executeUpdate方法,还是有写多余,因此可以抽取到一个类中。如果放在JDBCUtil类中,也不好,因为JDBCUtil是直接和数据交互的,因此可以新建立一个类CRUDTemplate。

    2. 抽取到CRUDTemplate中----最终抽取地方

     1 public class CRUDTemplate {
     2     /**
     3      * 重构DML操作
     4      */
     5     public static int executeUpdate(String sql,Object...params) {
     6         Connection connection=null;
     7         PreparedStatement pStatement=null;
     8         
     9         try {
    10             //1.加载驱动
    11             //2.连接数据库
    12             connection=JDBCUtil.getConnection();
    13             //3.创建语句
    14             pStatement=connection.prepareStatement(sql);
    15             //4.遍历参数
    16             for(int i=0;i<params.length;i++) {
    17                 pStatement.setObject(i+1, params[i]);
    18             }
    19             //4.执行语句
    20             return pStatement.executeUpdate();
    21         } catch (SQLException e) {
    22             // TODO Auto-generated catch block
    23             e.printStackTrace();
    24         }finally {
    25             JDBCUtil.close(connection, pStatement, null);
    26         }
    27         return 0;
    28     }
    29 
    30 }
    View Code
    1 public void save(Stu stu) {
    2         String sql="insert into stu(name,age) values(?,?)";
    3         CRUDTemplate.executeUpdate(sql,stu.getName(),stu.getAge());
    4     }
    View Code

    三. DQL抽取

    1. DQL抽取

     1 /**
     2      * DQL抽取
     3      */
     4     public static List<Stu> executeQuery(String sql,Object...params){
     5         Connection connection=null;
     6         PreparedStatement pStatement=null;
     7         ResultSet resultSet=null;
     8         //创建一个集合
     9         List<Stu> list=new ArrayList<Stu>();
    10         try {
    11             //1.加载驱动
    12             //2.连接数据库
    13             connection=JDBCUtil.getConnection();
    14             //3.创建语句
    15             pStatement=connection.prepareStatement(sql);
    16             //遍历参数
    17             for(int i=0;i<params.length;i++) {
    18                 pStatement.setObject(i+1, params[i]);
    19             }
    20             //4.执行语句
    21             resultSet=pStatement.executeQuery();
    22             while(resultSet.next()) {
    23                 Stu stu=new Stu();
    24                 stu.setName(resultSet.getString("name"));
    25                 stu.setAge(resultSet.getInt("age"));
    26                 stu.setId(resultSet.getInt("id"));
    27                 list.add(stu);
    28             }
    29             return list;
    30         }catch (Exception e) {
    31             e.printStackTrace();
    32         }finally {
    33             //5.释放资源
    34             JDBCUtil.close(connection, pStatement, resultSet);
    35         }
    36         return null;
    37     }
    View Code
     1 public Stu get(int id) {
     2         String sql="select *from stu where id=?";
     3         List<Stu> list=CRUDTemplate.executeQuery(sql, id);
     4         return list.size()==1?list.get(0):null;
     5     }
     6     
     7 
     8     public List<Stu> getAll() {
     9         String sql="select *from stu";
    10         return CRUDTemplate.executeQuery(sql);
    11     }
    View Code
     1 @Test
     2     public void testGet() {
     3         IStuDao dao=new StuDaoImpl();
     4         Stu student=dao.get(2);
     5         System.out.println(student);
     6         System.out.println(student.getName());
     7     }
     8 
     9     @Test
    10     public void testGetAll() {
    11         IStuDao dao=new StuDaoImpl();
    12         List<Stu> list=dao.getAll();
    13         System.out.println(list.toArray());
    14     }
    View Code

    2. 存在问题

    上面的DQL抽取虽然简单了,但是还存在一个问题,那就是在while循环中,只操作了Stu这个表格,写死了,但是,当表格很多,不仅仅想让它适用于Stu表,还想使用更多的表,就需要额外处理。因此,表的类型处理应该放在executeQuery方法之外来执行。

    四. 结果集处理代码实现

    1. 定义一个结果集处理接口

    1 package com.test.jdbctest.handler;
    2 
    3 import java.sql.ResultSet;
    4 import java.util.List;
    5 
    6 public interface IResultSetHandler {
    7     List handle(ResultSet rs);
    8 
    9 }
    View Code

    2. 在dao实现类中添加新的结果处理接口实现类

     1 class StuResultSetHandImp implements IResultSetHandler{
     2 
     3     public List handle(ResultSet rs) {
     4         List<Stu> list=new ArrayList<Stu>();
     5         try {
     6             while(rs.next()) {
     7                 Stu stu=new Stu();
     8                 stu.setName(rs.getString("name"));
     9                 stu.setAge(rs.getInt("age"));
    10                 stu.setId(rs.getInt("id"));
    11                 list.add(stu);
    12             }
    13         } catch (SQLException e) {
    14             // TODO Auto-generated catch block
    15             e.printStackTrace();
    16         }
    17         return list;
    18     }
    19 
    20 
    21 
    22 放在daoimpl类里面的末尾处
    View Code

    3. 修改template

     1 /**
     2      * DQL抽取
     3      */
     4     public static List<Stu> executeQuery(String sql,IResultSetHandler handler,Object...params){
     5         Connection connection=null;
     6         PreparedStatement pStatement=null;
     7         ResultSet resultSet=null;
     8         //创建一个集合
     9         List list=new ArrayList();
    10         try {
    11             //1.加载驱动
    12             //2.连接数据库
    13             connection=JDBCUtil.getConnection();
    14             //3.创建语句
    15             pStatement=connection.prepareStatement(sql);
    16             //4.执行语句
    17             resultSet=pStatement.executeQuery();
    18             return handler.handle(resultSet);
    19         }catch (Exception e) {
    20             e.printStackTrace();
    21         }finally {
    22             //5.释放资源
    23             JDBCUtil.close(connection, pStatement, resultSet);
    24         }
    25         return null;
    26     }
    View Code

    4. 使用泛型

    上面的结果集都是返回的list,但是有时候我们可能不仅仅是返回对象,有可能返回的是int的数量,比如查询共有多少行。因此,需要把返回类型改写成泛型,到时候调用的时候再决定返回什么类型。

    (1)修改结果处理集接口

    public interface IResultSetHandler<T> {
        T handle(ResultSet rs);
    
    }

    (2)修改实现

    class StuResultSetHandImp implements IResultSetHandler<List<Stu>>{
    
        public List<Stu> handle(ResultSet rs) {
            List<Stu> list=new ArrayList<Stu>();
            try {
                while(rs.next()) {
                    Stu stu=new Stu();
                    stu.setName(rs.getString("name"));
                    stu.setAge(rs.getInt("age"));
                    stu.setId(rs.getInt("id"));
                    list.add(stu);
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return list;
        }
        

    (3)修改template

    public static <T>T executeQuery(String sql,IResultSetHandler<T> handler,Object...params){
            Connection connection=null;
            PreparedStatement pStatement=null;
            ResultSet resultSet=null;
            try {
                //1.加载驱动
                //2.连接数据库
                connection=JDBCUtil.getConnection();
                //3.创建语句
                pStatement=connection.prepareStatement(sql);
                for(int i=0;i<params.length;i++) {
                    pStatement.setObject(i+1, params[i]);
                }
                //4.执行语句
                resultSet=pStatement.executeQuery();
                return handler.handle(resultSet);
            }catch (Exception e) {
                e.printStackTrace();
            }finally {
                //5.释放资源
                JDBCUtil.close(connection, pStatement, resultSet);
            }
            return null;
        }

    5. 存在问题

    发现其实每个表格查询做的事情差不多,如果每一个表都建立一个handler,是不好的。因此,可以统一处理:

    使用内省可以解决上面的问题。

    五. 内省

     1. 内省的简单使用

    假设有表stu,有id,name,age三个属性,且有对应的domain类

    现在做如下操作:

     1 class ClassTest{
     2     public Class class1;
     3     public ClassTest(Class class1) {
     4         this.class1=class1;
     5     }
     6 }
     7 public class Test {
     8     public static void main(String args[]) throws Exception {
     9         Stu stu=Stu.class.newInstance();
    10         //获取指定字节码的属性信息
    11         BeanInfo beanInfo=Introspector.getBeanInfo(Stu.class,Object.class);
    12         //获取所有的属性描述器
    13         PropertyDescriptor pds[]=beanInfo.getPropertyDescriptors();
    14         for(PropertyDescriptor pd:pds) {
    15             System.out.println(pd.getName());
    16             System.out.println(pd.getReadMethod());
    17             System.out.println(pd.getWriteMethod());
    18         }
    19         PropertyDescriptor propertyDescriptor=new PropertyDescriptor("name", Stu.class);
    20         System.out.println(propertyDescriptor.getName());
    21         propertyDescriptor.getWriteMethod().invoke(stu, "zhangsan");
    22         System.out.println(stu.getName());
    23     }
    24 
    25 }
    View Code
     1 age
     2 public java.lang.Integer com.test.jdbctest.domain.Stu.getAge()
     3 public void com.test.jdbctest.domain.Stu.setAge(java.lang.Integer)
     4 id
     5 public java.lang.Integer com.test.jdbctest.domain.Stu.getId()
     6 public void com.test.jdbctest.domain.Stu.setId(java.lang.Integer)
     7 name
     8 public java.lang.String com.test.jdbctest.domain.Stu.getName()
     9 public void com.test.jdbctest.domain.Stu.setName(java.lang.String)
    10 name
    11 zhangsan
    View Code

    2. 内省应用于结果处理集

    1)创建一个BeanHandler

    修改dao实现

    2)新建立BeanListHandler

    因此,上面每个类一个handerl就改成了BeanHanler和BeanListHandler了

    六. DBUtils

    之前几个章节都是介绍的如何一步步实现我们自己的JDBC重构,且可以把我们自己写的转换成jar包,以便自己项目中使用。实际上,有很多第三方很好用的JDBC工具,DBUtils就是其中的一款,它为我们提供了调用接口,我们直接使用就好。但是,底层的原理其实和我们之前学习的重构思想也有相似之处。可以接下来研究下。

    参考文献

    https://ke.qq.com/course/339214

  • 相关阅读:
    Java Nashorn--Part 4
    Java Nashorn--Part 3
    Java Nashorn--Part 2
    Java Nashorn--Part 1
    Java 异步 IO
    代码天天写,快乐天天有!
    比迷路更可怕的,是对读书的迷失。
    《寄生兽》观后感
    浅谈生活
    8月份的尾巴
  • 原文地址:https://www.cnblogs.com/Hermioner/p/10239285.html
Copyright © 2020-2023  润新知