zoukankan      html  css  js  c++  java
  • 抽取JDBCTemplate

    抽取JDBCTemplate

    为了解决DAO实现类中代码的重复问题,另外使得代码更通用,所以抽取一个公共的模板,使其更具有通用性。

    DAO实现类的代码

    public class StudentDAOImpl implements IStudentDAO {
    	public void save(Student stu) {
    		String sql = "INSERT INTO s_student(name,age) VALUES(?,?)";
    		Connection conn = null;
    		PreparedStatement ps = null;
    		try {
    			//加载注册驱动,获取连接对象
    			conn = JdbcUtil.getConn();
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, stu.getName());
    			ps.setInt(2, stu.getAge());
    			ps.executeUpdate();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}finally{
    			//释放资源
    			JdbcUtil.close(conn, ps, null);
    		}
    	}
    
    	public void delete(Long id) {
    		String sql = "DELETE FROM s_student WHERE id = ?";
    		Connection conn = null;
    		PreparedStatement ps = null;
    		try {
    			//加载注册驱动
    			//获取连接对象
    			conn = JdbcUtil.getConn();
    			//获取语句对象
    			ps = conn.prepareStatement(sql);
    			ps.setLong(1, id);
    			//执行sql语句
    			ps.executeUpdate();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}finally{
    			//释放资源
    			JdbcUtil.close(conn, ps, null);
    		}
    	}
    	public void update(Student newStu) {
    		String sql = "UPDATE s_student SET name = ?,age = ? WHERE id = ?;";
    		Connection conn = null;
    		PreparedStatement ps = null;
    		try {
    			//加载注册驱动
    			//获取连接对象
    			conn = JdbcUtil.getConn();
    			//获取语句对象
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, newStu.getName());
    			ps.setInt(2, newStu.getAge());
    			ps.setLong(3, newStu.getId());
    			//执行sql语句
    			ps.executeUpdate();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}finally{
    			//释放资源
    			JdbcUtil.close(conn, ps, null);
    		}
    	}
    
    	public Student get(Long id) {
    		String sql = "SELECT * FROM s_student WHERE id = ? "; 
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet rs = null;
    		try {
    			//加载注册驱动
    			//获取连接对象
    			conn = JdbcUtil.getConn();
    			// 获取语句对象
    			ps = conn.prepareStatement(sql);
    			ps.setLong(1, id);
    			// 执行SQL语句
    			rs = ps.executeQuery();
    			if (rs.next()) {
    				Student stu = new Student();
    				Long sid = rs.getLong("id");
    				String name = rs.getString("name");
    				Integer age = rs.getInt("age");
    
    				stu.setId(sid);
    				stu.setName(name);
    				stu.setAge(age);
    
    				return stu;
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			JdbcUtil.close(conn, ps, rs);
    		}
    		return null;
    	}
    
    	public List<Student> list() {
    		List<Student> list = new ArrayList<>();
    		String sql = "SELECT * FROM s_student";
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet rs = null;
    		try {
    			//加载注册驱动
    			//获取连接对象
    			conn = JdbcUtil.getConn();
    			//获取语句对象
    			ps = conn.prepareStatement(sql);
    			//执行sql语句
    			rs = ps.executeQuery(sql);
    			//查询操作
    			while(rs.next()){
    				Student stu = new Student();
    				Long id = rs.getLong("id");
    				String name = rs.getString("name");
    				Integer age = rs.getInt("age");
    				
    				stu.setName(name);
    				stu.setId(id);
    				stu.setAge(age);
    				
    				list.add(stu);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}finally{
    			JdbcUtil.close(conn, ps, rs);
    		}
    		return list;
    	}
    }
    

    发现save,delete,update方法的代码只有sql不同,所以,把公共的代码提出来放在模板类中的update方法中,把sql作为参数传到方法中。因为存在sql语句中的占位符并且站位符的个数并不确定,可以采用可变参数进行传参,把需要给站位符设置的站放在一个Object数组中,作为参数传到update方法中,在update方法中又把数组中的值迭代出来赋给特定的sql语句

    public void save(Student stu) {
    		String sql = "INSERT INTO  s_student(name,age) VALUES(?,?)";
    		JdbcTemplate.update(sql,stu.getName(),stu.getAge());
    	}
    
    	public void delete(Long id) {
    		String sql = "DELETE FROM s_student WHERE id = ?";
    		JdbcTemplate.update(sql, id);
    	}
    	
    	public void update(Student newStu) {
    		String sql = "UPDATE s_student SET name = ?,age = ? WHERE id = ?;";
    		JdbcTemplate.update(sql, newStu.getName(),newStu.getAge(),newStu.getId());
    	}
    

    模板中的update方法:

    	/**
    	 * DML语句的操作的模板
    	 * @param sql  sql语句 :UPDATE INSERT DELETE
    	 * @param params sql语句中的站位符? 对应值的数组
    	 * @return		返回受影响的行数
    	 */
    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;
    }
    

    query的抽取有些麻烦,因为它会返回一个结果集,处理结果集的行为,不应该作为模板中的代码,而是应该交给给自的DAO来完成,因为给自的DAO才知道各自表的列有哪一些,作为模板肯定只有在模板中调用DAO中处理完成后的结果集,但是为了保证传入query方法的参数是一致的,肯定需要定义一个规范,在程序中也就是定义一个接口,把这个接口就叫做结果集处理器,每一个DAO的实现类中要有一个处理结果的内部类,这个内部类去实现结果处理器接口,返回一个结果集供模板调用. 也就是,模板中query方法表面调用接口中的方法,实际调用的是各个DAO实现类中的结果集.这就是多态思想

    //结果集处理器
    public interface IResultSetHandler<T> {
    	T handle(ResultSet rs) throws Exception;
    }
    

    学生结果集处理器 实现了结果处理器接口

    public class StudentHandler implements IResultSetHandler<List<Student>>{
    
        @Override
        public List<Student> handle(ResultSet rs) throws Exception {
    
            List<Student> list = new ArrayList<>();
            while(rs.next()){
                Student stu = new Student();
                stu.setAge(rs.getInt("age"));
                stu.setId(rs.getLong("id"));
                stu.setName(rs.getString("name"));
    
                list.add(stu);
            }
            return list;
        }
    }
    

    DAO实现类中的get方法和list方法变成了:

    public Student get(Long id) {
        String sql = "SELECT * FROM s_student WHERE id = ? "; 
        List<Student> list = JdbcTemplate.query(sql,new StudentHandler(), id);
        return list.size() == 1?list.get(0) : null;
    }
    
    public List<Student> list() {
        String sql = "SELECT * FROM s_student";
        return JdbcTemplate.query(sql,new StudentHandler());
    }
    

    模板中的qurey方法

    //DQL语句的操作模板
    public static <T> T query(String sql,IResultSetHandler<T> ih,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]);
            }
            //执行sql语句
            rs = ps.executeQuery();
    
            //处理结果集
            return ih.handle(rs);
    
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtil.close(conn, ps, rs);
        }
        return null;
    }
    

    上述qurey方法抽取还存在一个问题就是,每个DAO实现类都得实现接口编写各自的结果处理器,如果DAO比较多,这个也就很麻烦了,能不能抽取值抽取一个更加通用的呢,那就得满足一定的规范,比如可以通过内省机制可以完成,但是列名必须和JavaBean的属性名相同。

    public class BeanHandler<T> implements IResultSetHandler<T>{
    	
    	private Class<T> classType = null;
    	public BeanHandler(Class<T> classType){
    		this.classType = classType;
    	}
    	@Override
    	public T handle(ResultSet rs) throws Exception {
    		//创建对应类的对象
    		T obj = classType.newInstance();
    		if(rs.next()){
    			BeanInfo info = Introspector.getBeanInfo(classType,Object.class);
    			PropertyDescriptor[] pds = info.getPropertyDescriptors();
    			for (PropertyDescriptor ps : pds) {
    				String column = ps.getName();
    				Object val = rs.getObject(column);
    				ps.getWriteMethod().invoke(obj,val);
    			}
    		}
    		return obj;
    	}
    }
    
    
    public class BeanListHandler<T> implements IResultSetHandler<List<T>>{
    	private Class<T> classType = null;
    	public BeanListHandler(Class<T> classType){
    		this.classType = classType;
    	}
    	@Override
    	public List<T> handle(ResultSet rs) throws Exception {
    		List<T> list = new ArrayList<>();
    		//创建对象
    		//获取对象描述器
    		while(rs.next()){
    			T obj = classType.newInstance();
    			BeanInfo info = Introspector.getBeanInfo(classType,Object.class);
    			PropertyDescriptor[] pds = info.getPropertyDescriptors();
    			for (PropertyDescriptor ps : pds) {
    				//获取对象的属性名,属性名和列名相同就调用setter方法把某一列的数据设置到对象中
    				String columnName = ps.getName();
    				Object val = rs.getObject(columnName);
    				ps.getWriteMethod().invoke(obj, val);
    			}
    			list.add(obj);
    		}
    		return list;
    	}
    
    }
    

    这时候的DAO实现类中方法可以这样来:

    public Student get(Long id) {
        String sql = "SELECT * FROM s_student WHERE id = ? "; 
        return JdbcTemplate.query(sql,new BeanHandler<>(Student.class), id);
    }
    
    public List<Student> list() {
        String sql = "SELECT * FROM s_student";
        return JdbcTemplate.query(sql, new BeanListHandler<>(Student.class));
    }
    
  • 相关阅读:
    HDU 5213 分块 容斥
    HDU 2298 三分
    HDU 5144 三分
    HDU 5145 分块 莫队
    HDU 3938 并查集
    HDU 3926 并查集 图同构简单判断 STL
    POJ 2431 优先队列
    HDU 1811 拓扑排序 并查集
    HDU 2685 GCD推导
    HDU 4496 并查集 逆向思维
  • 原文地址:https://www.cnblogs.com/tfper/p/9959031.html
Copyright © 2011-2022 走看看