抽取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));
}

抽取JDBCTemplate的更多相关文章

  1. jDialects:一个从Hibernate抽取的支持70多种数据库方言的原生SQL分页工具

    jDialects(https://git.oschina.net/drinkjava2/jdialects) 是一个收集了大多数已知数据库方言的Java小项目,通常可用来创建分页SQL和建表DDL语 ...

  2. Spring源码解析-JdbcTemplate

    JdbcTemplate类图 从类继承关系上来看,JdbcTemplate继承了基类JdbcAccessor和接口类JdbcOperation,在基类JdbcAccessor的设计中,对DataSou ...

  3. 【翻译】spring-data 之JdbcTemplate 使用

    文档 Jdbc的使用 基础的代码结构: 一个Application作为入口.IUserRepository和UserRepository作为具体的实现.applicationContext.xml定义 ...

  4. 阶段3 2.Spring_09.JdbcTemplate的基本使用_6 JdbcDaoSupport的使用以及Dao的两种编写方式

    复制三个出来.分别叫做 OrderDaoImpl.ProductDaoImpl.UserDaoImpl 复制这三个出来就是为了解决重复性代码的问题. 每个dao中都有这段代码.这些都是重复性的代码.在 ...

  5. Spring 系列之jdbcTemplate的使用

    Spring系列之 jdbcTemplate 啥是jdncTemplate? t他是spring框架中提供的一个对象,是对原始的jdbcAPI对象的简单封装,spring框架为我们提供了很多操作,模板 ...

  6. Spring(四)Spring JdbcTemplate&声明式事务

    JdbcTemplate基本使用 01-JdbcTemplate基本使用-概述(了解) JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装.spr ...

  7. JdbcTemplate+PageImpl实现多表分页查询

    一.基础实体 @MappedSuperclass public abstract class AbsIdEntity implements Serializable { private static ...

  8. 使用rowid抽取数据方法以及大数据量游标卡住的应对

    平时工作的时候,经常会遇到这种事情,从一个大表A中,抽取字段a在一个相对较小B的表的数据,比如,从一个详单表中,抽取几万个用户号码的话单出来.这种时候,一般来说, 做关联查询: create tabl ...

  9. TODO:从数据库中随机抽取一条记录

    TODO:从数据库中随机抽取一条记录 1.最直接,最粗暴的方法先计算记录的总数,然后选择一个从0到记录总数之间的随机数n,利用skip跳过n条记录,这是效率低下的的方法,首先的记录总数,在用skip会 ...

随机推荐

  1. try with resources简洁的异常捕获机制

    通过前篇的<Java文件IO流的操作总结>,我们知道了基本输入输出流的使用方式,但是每次都需要在finally处关闭流资源,这样操作起来既啰嗦又麻烦,有没有更简洁的方式呢?本篇就来讲解jd ...

  2. Python3.x:生成器简介

    Python3.x:生成器简介 概念 任何使用yield的函数都称之为生成器:使用yield,可以让函数生成一个序列,该函数返回的对象类型是"generator",通过该对象连续调 ...

  3. Python3.6(windows系统)安装pip.whl

    Python3.6(windows系统)安装pip.whl 1,下载whl文件:https://pypi.python.org/pypi/pip#downloads 2,将下载的文件放入Python的 ...

  4. 20145219《网络对抗》PC平台逆向破解

    20145219<网络对抗>PC平台逆向破解 shellcode注入 1.shellcode shellcode是一段代码,溢出后,执行这段代码能开启系统shell. 2.构造方法 (1) ...

  5. HeyWeGo第五周项目总结

    HeyWeGo第五周项目总结 项目内容 使用java程序开发一款扫雷游戏 游戏项目规划: 确定游戏中方块格子的个数 确定游戏中地雷的个数(初始10个),完成布雷 计算每个方块周围的雷数,在方块周围本身 ...

  6. Block作为参数时的使用

    Block作为参数使用,常见于各框架之中,比如在封装一个类时,当做什么事情由外界去决定,什么时候调用由自己的类决定时,这时候就需要将block作为参数使用. 下面我们模仿AFNetworking的ma ...

  7. jQuery实现鼠标点击Div区域外隐藏Div

    冒泡定义:当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发.这一过程被称为事件冒泡:这个事件从原始元素开始一直冒泡到DOM树的最上层.(摘自网络 ...

  8. UVa 11538 象棋中的皇后

    https://vjudge.net/problem/UVA-11538 题意: n×m的棋盘,有多少种方法放置两个相互攻击的皇后? 思路: 这两个皇后互相攻击的方式只有3种,在同一行,在同一列,或在 ...

  9. 前端工程化 - bower

    什么是bower bower是前端的包管理工具,类似于php的composer,python的pip,虽然先如今bower已经停止了更新(主要是因为Browserify和Webpack等包管理工具的兴 ...

  10. 使用向量化的 if:ifelse

    进行分支计算的一个替代方法是 ifelse( ).这个函数接收一个逻辑向量作为判定条件,并且返回一个向量.对于逻辑判定条件内的每一个元素,若是 TRUE,则选择第 2个参数 yes 中所对应的元素:若 ...