日期:2014-05-16  浏览次数:20439 次

对spring JdbcTemplate的一个扩展(使其支持单Connection)
对spring JdbcTemplate的一个扩展(使其支持单Connection).

不怕大家笑话,以前一直没怎么使用过spring jdbc template,
印象中只用过
public List queryForList(String sql, Object[] args)
public Map queryForMap(String sql, Object[] args)
和SqlFunction

在orm大行其道,spring诞生快一个实际的今天,再来探讨jdbc的一些封装实在不知道有没有意义.
不过还是想把刚刚弄出来的一点东西和大家分享.

看了一下 JdbcTemplate,
发现起核心是那几个 execute 方法.
而那几个execute方法的机构大概是这样(重点讨论Connection,所以其他地方从简)

execute方法开始

  Connection con = DataSourceUtils.getConnection(getDataSource());

  // 做一些数据库操作

  DataSourceUtils.releaseConnection(con, getDataSource());

execute方法结束


当你要批量执行一些操作时(不是 每个操作使用不同的sql,或者是其他不适合 addBatch的情形).

如下:
JdbcTemplate jdbcTemplate=new JdbcTemplate(ds);
jdbcTemplate.query(sql_1, args_1,rch_1);
jdbcTemplate.query(sql_2, args_2,rch_2);
jdbcTemplate.query(sql_3, args_3,rch_3);
jdbcTemplate.query(sql_4, args_4,rch_4);
......


此时,在内部实际上执行了,n次 getConnection,releaseConnection.

而这些操作,在很多时候,是可以通过一个Connection来完成的.

我的扩展就是实现了这个功能.


JdbcTemplatePlus jdbcTemplate=new JdbcTemplatePlus(ds);
// 内部使用一个唯一的Connection
jdbcTemplate.setUseOneConnection(true);
jdbcTemplate.query(sql_1, args_1,rch_1);
jdbcTemplate.query(sql_2, args_2,rch_2);
jdbcTemplate.query(sql_3, args_3,rch_3);
jdbcTemplate.query(sql_4, args_4,rch_4);
......
// 最后调用该方法 释放那个内部唯一的Connection
// 虽然我在finalize 里调用了,不过finalize毕竟不是总能在正确的时间被正确的调用
jdbcTemplate.releaseConnection();




我们系统中,有大量的嵌套查询.使用该JdbcTemplatePlus的唯一Connection特性后,类似的操作速度提升明显.
(不过可能我们原先的做法不对,也许 spring内部已经实现这个机制了 这些我就不明白了,欢迎大家来指正)
我们原先的做法(伪代码):

public List queryNsubQueryUserList(Map param){

	// 外层查询
	final String bsql="select * from ......";
	final JdbcTemplate jdbcTemplate=createJdbcTemplate();
	
	// 子查询相关
	final String subSql="select ............ ";
	final JdbcTemplate subJdbcTemplate=createJdbcTemplate();
	
	List rslist=jdbcTemplate.query(bsql.toString(),sqlArg, 
		new ResultSetHandler(){
			public void processRow(ResultSet rs) throws SQLException {
				final 一个VO recordObj=new 一个VO();
				// 子查询
				subJdbcTemplate.query(subSql, subQueryArgs, 
					new ResultSetHandler(){
						public void processRow(ResultSet rs) throws SQLException {
							// 一些操作........
						}
					}
				);
					// 一些操作........
					recordObj.setXXXXX(rs.getString("XXXXX"));
					.........
					// 将记录放入集合
					addRecord(recordObj);
			}
		}
	);
	return rslist;
	}
}


在使用 JdbcTemplatePlus 代替 JdbcTemplate,并设置.setUseOneConnection(true)后,
耗时变为原先的1/8左右.


扩展的 JdbcTemplatePlus 代码如下,欢迎大家拍砖,挑错.
对 execute方法的修改如下:
把所有的 this.ativeJdbcExtractor换成 getNativeJdbcExtractor(), 这个是必须的 呵呵.

把所有 Connection con = DataSourceUtils.getConnection(getDataSource()); 换成
Connection con = tryGetConnection();

把所有 DataSourceUtils.releaseConnection(con, getDataSource());  换成
tryReleaseConnection(con);


package com.neusoft.tdframework.dao;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ParameterDisposer;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.SqlProvider;
import org.springframework.jdbc.core.StatementCallback;
import org.springframewor