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

posted @ 2019-01-08 16:03  Hermioner  阅读(393)  评论(0编辑  收藏  举报