• 抽取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));
    }
    
  • 相关阅读:
    自定义 sql Split函数 / 自定义mp_helptext查看存储
    easyUI 节点树选择
    EasyUI手风琴 Tab卡使用
    水晶报表分组,统计,求和,sum()函数使用
    华硕GL502VSK处理器使用XTU降压。
    .
    bootstrap4元素居左居右
    关于npm run dev报错npm ERR! missing script: dev
    使用Vue写一个登陆页面并在管理页面查看和修改
    localStorage注册页面A注册数据在本地储存并在B页面打开
  • 原文地址:https://www.cnblogs.com/tfper/p/9959031.html
Copyright © 2020-2023  润新知