對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);
-
- 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);
- ......
-
-
- 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.springframework.jdbc.datasource.DataSourceUtils;
- import org.springframework.jdbc.support.JdbcUtils;
- import org.springframework.util.Assert;
-
- public class JdbcTemplatePlus extends JdbcTemplate {
-
- private Connection connection=null;
- private boolean useOneConnection=false;
-
-
- public JdbcTemplatePlus() {
- super();
- }
- public JdbcTemplatePlus(DataSource dataSource) {
- super(dataSource);
- }
- public JdbcTemplatePlus(DataSource dataSource, boolean lazyInit) {
- super(dataSource,lazyInit);
- }
-
- private Connection tryGetConnection(){
- if (useOneConnection){
- if (connection==null){
- connection= DataSourceUtils.getConnection(getDataSource());
- }
- return connection;
- }
- return DataSourceUtils.getConnection(getDataSource());
- }
-
- private void tryReleaseConnection(Connection con){
- if (!useOneConnection){
- DataSourceUtils.releaseConnection(con, getDataSource());
- }
- }
-
- public Connection getConnection(){
- return connection;
- }
-
- public void setConnection(Connection connection){
- this.connection=connection;
- }
-
- public boolean isUseOneConnection() {
- return useOneConnection;
- }
-
- public void setUseOneConnection(boolean useOneConnection) {
- this.useOneConnection = useOneConnection;
- }
-
- public void releaseConnection(){
- DataSourceUtils.releaseConnection(connection, getDataSource());
- }
-
-
-
-
- public static String getSql(Object sqlProvider) {
- if (sqlProvider instanceof SqlProvider) {
- return ((SqlProvider) sqlProvider).getSql();
- }
- else {
- return null;
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
- public Object execute(ConnectionCallback action) throws DataAccessException {
- Assert.notNull(action, "Callback object must not be null");
-
- Connection con = tryGetConnection();
- try {
- Connection conToUse = con;
- if (getNativeJdbcExtractor() != null) {
- conToUse = getNativeJdbcExtractor().getNativeConnection(con);
- } else {
- conToUse = createConnectionProxy(con);
- }
- return action.doInConnection(conToUse);
- } catch (SQLException ex) {
- tryReleaseConnection(con);
- con = null;
- throw getExceptionTranslator().translate("ConnectionCallback",
- getSql(action), ex);
- } finally {
- tryReleaseConnection(con);
- }
- }
-
- public Object execute(StatementCallback action) throws DataAccessException {
- Assert.notNull(action, "Callback object must not be null");
-
- Connection con = tryGetConnection();
- Statement stmt = null;
- try {
- Connection conToUse = con;
- if (getNativeJdbcExtractor() != null
- && getNativeJdbcExtractor()
- .isNativeConnectionNecessaryForNativeStatements()) {
- conToUse = getNativeJdbcExtractor().getNativeConnection(con);
- }
- stmt = conToUse.createStatement();
- applyStatementSettings(stmt);
- Statement stmtToUse = stmt;
- if (getNativeJdbcExtractor() != null) {
- stmtToUse = getNativeJdbcExtractor().getNativeStatement(stmt);
- }
- Object result = action.doInStatement(stmtToUse);
- handleWarnings(stmt.getWarnings());
- return result;
- } catch (SQLException ex) {
- JdbcUtils.closeStatement(stmt);
- stmt = null;
- tryReleaseConnection(con);
- con = null;
- throw getExceptionTranslator().translate("StatementCallback",
- getSql(action), ex);
- } finally {
- JdbcUtils.closeStatement(stmt);
- tryReleaseConnection(con);
- }
- }
-
- public Object execute(PreparedStatementCreator psc,
- PreparedStatementCallback action) throws DataAccessException {
-
- Assert.notNull(psc, "PreparedStatementCreator must not be null");
- Assert.notNull(action, "Callback object must not be null");
- if (logger.isDebugEnabled()) {
- String sql = getSql(psc);
- logger.debug("Executing prepared SQL statement"
- + (sql != null ? " [" + sql + "]" : ""));
- }
-
- Connection con = tryGetConnection();
- PreparedStatement ps = null;
- try {
- Connection conToUse = con;
- if (getNativeJdbcExtractor() != null
- && getNativeJdbcExtractor()
- .isNativeConnectionNecessaryForNativePreparedStatements()) {
- conToUse = getNativeJdbcExtractor().getNativeConnection(con);
- }
- ps = psc.createPreparedStatement(conToUse);
- applyStatementSettings(ps);
- PreparedStatement psToUse = ps;
- if (getNativeJdbcExtractor() != null) {
- psToUse = getNativeJdbcExtractor()
- .getNativePreparedStatement(ps);
- }
- Object result = action.doInPreparedStatement(psToUse);
- handleWarnings(ps.getWarnings());
- return result;
- } catch (SQLException ex) {
- if (psc instanceof ParameterDisposer) {
- ((ParameterDisposer) psc).cleanupParameters();
- }
- String sql = getSql(psc);
- psc = null;
- JdbcUtils.closeStatement(ps);
- ps = null;
- tryReleaseConnection(con);
- con = null;
- throw getExceptionTranslator().translate(
- "PreparedStatementCallback", sql, ex);
- } finally {
- if (psc instanceof ParameterDisposer) {
- ((ParameterDisposer) psc).cleanupParameters();
- }
- JdbcUtils.closeStatement(ps);
- tryReleaseConnection(con);
- }
- }
-
- public Object execute(CallableStatementCreator csc,
- CallableStatementCallback action) throws DataAccessException {
-
- Assert.notNull(csc, "CallableStatementCreator must not be null");
- Assert.notNull(action, "Callback object must not be null");
- if (logger.isDebugEnabled()) {
- String sql = getSql(csc);
- logger.debug("Calling stored procedure"
- + (sql != null ? " [" + sql + "]" : ""));
- }
-
- Connection con = tryGetConnection();
- CallableStatement cs = null;
- try {
- Connection conToUse = con;
- if (getNativeJdbcExtractor() != null) {
- conToUse = getNativeJdbcExtractor().getNativeConnection(con);
- }
- cs = csc.createCallableStatement(conToUse);
- applyStatementSettings(cs);
- CallableStatement csToUse = cs;
- if (getNativeJdbcExtractor() != null) {
- csToUse = getNativeJdbcExtractor()
- .getNativeCallableStatement(cs);
- }
- Object result = action.doInCallableStatement(csToUse);
- handleWarnings(cs.getWarnings());
- return result;
- } catch (SQLException ex) {
-
-
-
-
- if (csc instanceof ParameterDisposer) {
- ((ParameterDisposer) csc).cleanupParameters();
- }
- String sql = getSql(csc);
- csc = null;
- JdbcUtils.closeStatement(cs);
- cs = null;
- tryReleaseConnection(con);
- con = null;
- throw getExceptionTranslator().translate(
- "CallableStatementCallback", sql, ex);
- } finally {
- if (csc instanceof ParameterDisposer) {
- ((ParameterDisposer) csc).cleanupParameters();
- }
- JdbcUtils.closeStatement(cs);
- tryReleaseConnection(con);
- }
- }
-
-
- protected void finalize() throws Throwable{
- super.finalize();
- releaseConnection();
- }
-
-
-
- }