企划做网站,网站建设台州,网页模板下载在线,黄页网址大全免费上一篇中系统总结了模板模式的原理和使用#xff0c;提到了模板方法和回调接口。回调接口和模板方法类之间的关系可以看作服务与被服务的关系#xff0c;模板方法类想要回调接口做事#xff0c;就要提供相应的资源#xff0c;接口用提供的资源做事#xff0c;完事后#…上一篇中系统总结了模板模式的原理和使用提到了模板方法和回调接口。回调接口和模板方法类之间的关系可以看作服务与被服务的关系模板方法类想要回调接口做事就要提供相应的资源接口用提供的资源做事完事后模板方法类来处理公开的资源回调接口不需要在关心这些。今天再记录一下JDBCTemplate中模板方法模式的应用。
这里先给出JDBC的初级代码
public class JDBCTemplateT {/*** inset updata delect操作时调用此方法*/public void update(String sql,Object... params){Connection con null;PreparedStatement ps null;int count 0;try {con JDBCUtil.getConnection();ps con.prepareStatement(sql);if (params ! null) {for (int i 0; i params.length; i) {ps.setObject(i1, params[i]);}}count ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {//connection不能关闭因为还要在Service中使用
// JDBCUtil.close(con, ps);JDBCUtil.close(null, ps);}} /*** 执行查询时用的方法* param sql* param rm* param params* return*/public ListT query(String sql,RowMapper rm,Object... params){Connection con null;PreparedStatement ps null;ResultSet rs null;List result new ArrayList();try {con JDBCUtil.getConnection();ps con.prepareStatement(sql);if (params ! null) {for (int i 0; i params.length; i) {ps.setObject(i1, params[i]);}}rs ps.executeQuery();while(rs.next()){Object obj rm.mapRow(rs);result.add(obj);}} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(null, ps, rs);}return result;} public Object query4Object(String sql,RowMapper rm,Object... params){List data query(sql, rm, params);return data.isEmpty() ? null :data.get(0);}}
上面的代码把对数据库的访问操作封装成了两个方法对于update(String sql,Object... params)方法在实际的开发中新增数据有时需要记录新增数据的主键在JDBC中提供了这样一个方法
con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
因此con.prepareStatement(sql)的参数如果写死是不能满足需求的。基于模板模式的思路定义专门创建PreparedStatement对象的接口
public interface PreparedStatementCreater {/*** 创建PreparedStatement对象* param con* return*/public PreparedStatement createPreparedStatement(Connection con,KeyHolder keyHolder) throws Exception;
}
然后prepareStatement的创建和sql传参和赋值全部交给调用者实现我只负责运行 /*** 当保存需要返回主键的时候调用此方法* param psc 用于创建PreparedStatement对象* param keyHolder 用于存放主键*/public void update(PreparedStatementCreater psc,KeyHolder keyHolder){Connection con null;PreparedStatement ps null;ResultSet rs null;int count 0;try {con JDBCUtil.getConnection();
// ps con.prepareStatement(sql);
//
// if (params ! null) {
// for (int i 0; i params.length; i) {
// ps.setObject(i1, params[i]);
// }
// }//prepareStatement交给调用者创建我只负责运行其他的不再关心ps psc.createPreparedStatement(con, keyHolder);ps.executeUpdate();rs ps.getGeneratedKeys();List keys new ArrayList();//保存返回主键的代码ResultSetMetaData rsmd rs.getMetaData();int columnCount rsmd.getColumnCount();if (rs.next()){for (int i0;icolumnCount;i){keys.add(rs.getObject(i1));}}//返回值是void用keyHolder返回主键调用者传空的keyHolder进来keyHolder.setList(keys);} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(null, ps , rs);}}public class KeyHolder {private List list;public KeyHolder() {list new ArrayList();}public KeyHolder(List list) {this.list list;}public void setList(List list) {this.list list;}/**联合主键*/public List getKeyList() {return list;}/**单个主键*/public Object getKey(){if(list.isEmpty()){return null;}return list.get(0);}
}
此时当调用者调用update方法时迫使实现PreparedStatementCreater 接口中的createPreparedStatement方法。
对于public ListT query(String sql,RowMapper rm,Object... params)方法如果我要查询一个部门对象并把部门对应的员工映射进来时根据查询结果逐条映射的逻辑是不对的
while(rs.next())
{Object obj rm.mapRow(rs);result.add(obj);
}
select * from dept d inner join emp e on e.dept_idd.id
此时多条数据映射一个部门对象根据查询结果集逐条映射的逻辑是不对的因此查询方法也要进行改造同样是通过的传入接口迫使调用者实现剩余逻辑的方法来做 /*** 执行查询时用的方法* 当进行一方查询多方数据时使用此方法 一个部门对应多个员工 dept ListEmp* param sql* param params* return*/public Object query(String sql,ResultSetExtractor rse, Object... params){Connection con null;PreparedStatement ps null;ResultSet rs null;Object obj new Object();try {con JDBCUtil.getConnection();ps con.prepareStatement(sql);if (params ! null) {for (int i 0; i params.length; i) {ps.setObject(i1, params[i]);}}rs ps.executeQuery();obj rse.extractData(rs);} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(null, ps, rs);}return obj;}
以上就是JDBC封装中对模板方法的使用。
在spring中正是根据这种思想实现各种JDBCTemplate中的各种模板方法通过相应回调接口所公开的API自由度的大小简单分为4组
面向Connection的模板方法。通过ConnectionCallback接口公开java.sql.Connection进行数据访问不需要关心连接的释放和获取但自由度很大一般避免直接使用面向Connection接口的模板方法进行数据访问。
面向Statement的模板方法。主要处理基于静态sql的数据访问请求。通过StatementCallback接口对外公开java.sql.Statement缩小了回调接口内的权限范围相比上一种提高了安全性。
面向PreparedStatement的模板方法。通过PreparedStatementCreater接口公开Connection允许PreparedStatement创建创建需要传入包含参数的SQLPreparedStatement创建之后公开给PreparedStatementCallback回调接口。
面向CallableStatement的模板方法。通过CallableStatementCreater接口公开Connection以便创建用于调用存储过程的CallableStatement再通过CallableStatementCallback公开创建的CallableStatement实现基于存储过程的数据访问。