抽取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)); }
共同学习,写下你的评论
评论加载中...
作者其他优质文章