JDBC(七)操作模板:JdbcTemplate

怎么做重构:

思想:大家来找茬.
两段功能相同的代码,发现他们的共同点,提取出去(把操作模板提出取出).

把共同的代码提取到:
1:可以提取到父类中--->不推荐,容易导致子类爆炸.
2:使用组合方式,推荐.

抽取JdbcTemplate的重要性:
1):凡是搞过JDBC,2~3年的程序员,都可以轻松的写出JdbcTemplate.
2):学习,如何做重构.
3):类似于dbutils组件/Spring JdbcTemplate.
4):之后做的高级查询+分页+深入重构设计,都会基于JdbcTemplate来.
5):模拟Hibernate.

没有操作模板的写法

JDBC(七)操作模板:JdbcTemplate_第1张图片
Paste_Image.png

DML操作模板

JdbcTemplate

public class JdbcTemplate {
    
    public static int update(String sql,Object... params){
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            conn=JdbcUtil.getConn();
            ps=conn.prepareStatement(sql);
            //设置占位参数
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i+1, params[i]);
            }
            return ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JdbcUtil.close(conn, ps, null);
        }
        return 0;
    }
}

test

public class JdbcTemplateTest {
    
    
    public void save(Student stu){
        String sql = "INSERT INTO t_student (NAME, age) VALUES (?,?);";
        Object[] params={stu.getName(),stu.getAge()};
        JdbcTemplate.update(sql, params);
    }
    
    
    public void delete(Long id){
        String sql = "DELETE FROM t_student WHERE id = ?";
        JdbcTemplate.update(sql, id);
    }
    
    public void update(Student stu){
        String sql = "UPDATE t_student SET name = ?,age= ? WHERE id =?";
        Object[] params={stu.getName(),stu.getAge(),stu.getId()};
        JdbcTemplate.update(sql, params);
    }

}

DQL操作模板

第一个版本

public static List query(String sql,Object... params){
        List list = new ArrayList();
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn=JdbcUtil.getConn();
            ps=conn.prepareStatement(sql);
            //设置占位参数
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i+1, params[i]);
            }
            rs= ps.executeQuery();
            while(rs.next()){
                Student stu = new Student();
                stu.setName(rs.getString("name"));
                stu.setAge(rs.getInt("age"));
                stu.setId(rs.getLong("id"));
                list.add(stu);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JdbcUtil.close(conn, ps, null);
        }
        return list;
    }
public  Student getSingle(Long id){
        String sql = "SELECT * FROM t_student WHERE id = ?";
        List list=JdbcTemplate.query(sql, id);
        return list.size()==1?list.get(0):null;
    }
    
    
    public  List list(Long id){
        String sql = "SELECT * FROM t_student WHERE";
        return JdbcTemplate.query(sql);
    }

上面的代码:从查询学生对象上来说,没有一点问题.
但是:因为在JdbcTemplate的query方法中,写死了Student和t_student表的三个列---->该query方法只能操作当前的Student对象和t_student表.是不能操作Teacher对象/t_teacher表的.

第二个版本
不同的对象(不同的表),不同的表有不同的列,列都不同了,处理结果集的代码就不相同.
只能说:每一个DAO的查询方法都应该要处理结果集,但是怎么处理,只有各自的DAO才知道.
也就是说:处理结果集的行为,不应该作为模板中的代码,而是应该交给给自的DAO来完成,因为给自的DAO才知道各自表的列有哪一些.

规定:所有的处理结果集的方法都叫做handle(在Java中做规范就是接口).
IResultSetHandler

public interface IResultSetHandler {
    
    List handle(ResultSet rs) throws SQLException;

}

StudentResultSetHandler

public class StudentResultSetHandler implements IResultSetHandler {

    public List handle(ResultSet rs) throws SQLException {
        List list=new ArrayList();
        while(rs.next()){
            Student stu = new Student();
            stu.setName(rs.getString("name"));
            stu.setAge(rs.getInt("age"));
            stu.setId(rs.getLong("id"));
            list.add(stu);
        }
        return list;
    }

}

查询模板

public static List query(String sql,IResultSetHandler handler,Object... params){
        
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn=JdbcUtil.getConn();
            ps=conn.prepareStatement(sql);
            //设置占位参数
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i+1, params[i]);
            }
            rs= ps.executeQuery();
            return handler.handle(rs);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JdbcUtil.close(conn, ps, null);
        }
        return new ArrayList();
    }

具体查询调用

public  List list(Long id){
        String sql = "SELECT * FROM t_student";
        List list=JdbcTemplate.query(sql,new StudentResultSetHandler());
        return list;
    }

第三个版本
第二个操作模板:query方法,还不太高级.如果要查询结果总数:

SELECT COUNT(id) FROM t_student; 

应该返回一个整数,而不是集合。也就说:处理结果只会,到底应该返回什么类型,其实是不确定的,不同调用者的返回类型是不一样的.不能使用List就以偏概全.
解决方案:使用泛型.

public interface IResultSetHandler2 {
    
    T handle(ResultSet rs) throws SQLException;
}
public class StudentResultSetHandler2 implements IResultSetHandler2>{

    public List handle(ResultSet rs) throws SQLException {
        List list=new ArrayList();
        while(rs.next()){
            Student stu = new Student();
            stu.setName(rs.getString("name"));
            stu.setAge(rs.getInt("age"));
            stu.setId(rs.getLong("id"));
            list.add(stu);
        }
        return list;
    }
}
//查询全部对象
    public  List list2(){
        String sql = "SELECT * FROM t_student";
        List list=JdbcTemplate.query2(sql,new StudentResultSetHandler2());
        System.out.println("count:"+list.size());
        return list;
    }
    
    
    //查询数量
    public  void list3(){
        String sql = "SELECT COUNT(id) FROM t_student";
        Long count=JdbcTemplate.query2(sql,new IResultSetHandler2(){

            public Long handle(ResultSet rs) throws SQLException {
                if(rs.next()){
                    return rs.getLong(1);
                }
                return 0L;
            }
        });
        System.out.println("count:"+count);
    }

第四个版本
在第三个版本的基础上,但是冗余了具体的databean,可以再抽象:

模拟Hibernate

public class Hibernate {
    
    
    public static void save(Object obj){
        try {
            //获取对象对应的表名
            String tableName=obj.getClass().getSimpleName();
            Table table=obj.getClass().getAnnotation(Table.class);
            if(table!=null){
                tableName=table.getValue();
            }
            StringBuilder sql=new StringBuilder();
            sql.append("INSERT INTO").append(tableName).append("(");
            StringBuilder columnSql=new StringBuilder(); //拼接需要插入哪些列表的sql:
            StringBuilder placeHolderSql=new StringBuilder();//拼接占位符的SQL:??
            List params=new ArrayList();  //参数
            BeanInfo beanInfo=Introspector.getBeanInfo(obj.getClass(),Object.class);
            PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor pd : pds) {
                //对象中的属性名
                String propertyName=pd.getName();
                if("id".equals(propertyName)){
                    columnSql.append(propertyName).append(",");
                    placeHolderSql.append("?").append(",");
                    //获取属性的值,调用属性的getter方法
                    Object val=pd.getReadMethod().invoke(obj);
                    params.add(val);
                }
            }
            //删除最后一个
            columnSql.deleteCharAt(columnSql.length()-1);
            placeHolderSql.deleteCharAt(placeHolderSql.length()-1);
            sql.append(columnSql);
            sql.append(") VALUES (");
            sql.append(placeHolderSql);
            sql.append(")");
            System.out.println("SQL= "+sql);
            System.out.println("params= "+params);
            JdbcTemplate.update(sql.toString(), params.toArray());
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

 

                            
                        
                    
                    
                    

你可能感兴趣的:(JDBC(七)操作模板:JdbcTemplate)