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

关键字: Spring   sping    

对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,所以其他地方从简)

 

代码
  1. execute方法开始   
  2.   
  3.   Connection con = DataSourceUtils.getConnection(getDataSource());   
  4.   
  5.   // 做一些数据库操作   
  6.   
  7.   DataSourceUtils.releaseConnection(con, getDataSource());   
  8.   
  9. execute方法结束   
<script>render_code();</script>

 

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

如下:

代码
  1. JdbcTemplate jdbcTemplate=new JdbcTemplate(ds);   
  2. jdbcTemplate.query(sql_1, args_1,rch_1);   
  3. jdbcTemplate.query(sql_2, args_2,rch_2);   
  4. jdbcTemplate.query(sql_3, args_3,rch_3);   
  5. jdbcTemplate.query(sql_4, args_4,rch_4);   
  6. ......   
<script>render_code();</script>

 

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

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

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

 

代码
  1.   
  2. JdbcTemplatePlus jdbcTemplate=new JdbcTemplatePlus(ds);   
  3. // 内部使用一个唯一的Connection   
  4. jdbcTemplate.setUseOneConnection(true);   
  5. jdbcTemplate.query(sql_1, args_1,rch_1);   
  6. jdbcTemplate.query(sql_2, args_2,rch_2);   
  7. jdbcTemplate.query(sql_3, args_3,rch_3);   
  8. jdbcTemplate.query(sql_4, args_4,rch_4);   
  9. ......   
  10. // 最后调用该方法 释放那个内部唯一的Connection   
  11. // 虽然我在finalize 里调用了,不过finalize毕竟不是总能在正确的时间被正确的调用   
  12. jdbcTemplate.releaseConnection();   
  13.   
<script>render_code();</script>

 

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

代码
  1.   
  2. public List queryNsubQueryUserList(Map param){   
  3.   
  4.     // 外层查询   
  5.     final String bsql="select * from ......";   
  6.     final JdbcTemplate jdbcTemplate=createJdbcTemplate();   
  7.        
  8.     // 子查询相关   
  9.     final String subSql="select ............ ";   
  10.     final JdbcTemplate subJdbcTemplate=createJdbcTemplate();   
  11.        
  12.     List rslist=jdbcTemplate.query(bsql.toString(),sqlArg,    
  13.         new ResultSetHandler(){   
  14.             public void processRow(ResultSet rs) throws SQLException {   
  15.                 final 一个VO recordObj=new 一个VO();   
  16.                 // 子查询   
  17.                 subJdbcTemplate.query(subSql, subQueryArgs,    
  18.                     new ResultSetHandler(){   
  19.                         public void processRow(ResultSet rs) throws SQLException {   
  20.                             // 一些操作........   
  21.                         }   
  22.                     }   
  23.                 );   
  24.                     // 一些操作........   
  25.                     recordObj.setXXXXX(rs.getString("XXXXX"));   
  26.                     .........   
  27.                     // 将记录放入集合   
  28.                     addRecord(recordObj);   
  29.             }   
  30.         }   
  31.     );   
  32.     return rslist;   
  33.     }   
  34. }   
  35.   
<script>render_code();</script>
在使用 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);

 

代码
  1.   
  2. package com.neusoft.tdframework.dao;   
  3.   
  4. import java.sql.CallableStatement;   
  5. import java.sql.Connection;   
  6. import java.sql.PreparedStatement;   
  7. import java.sql.SQLException;   
  8. import java.sql.Statement;   
  9.   
  10. import javax.sql.DataSource;   
  11.   
  12. import org.springframework.dao.DataAccessException;   
  13. import org.springframework.jdbc.core.CallableStatementCallback;   
  14. import org.springframework.jdbc.core.CallableStatementCreator;   
  15. import org.springframework.jdbc.core.ConnectionCallback;   
  16. import org.springframework.jdbc.core.JdbcTemplate;   
  17. import org.springframework.jdbc.core.ParameterDisposer;   
  18. import org.springframework.jdbc.core.PreparedStatementCallback;   
  19. import org.springframework.jdbc.core.PreparedStatementCreator;   
  20. import org.springframework.jdbc.core.SqlProvider;   
  21. import org.springframework.jdbc.core.StatementCallback;   
  22. import org.springframework.jdbc.datasource.DataSourceUtils;   
  23. import org.springframework.jdbc.support.JdbcUtils;   
  24. import org.springframework.util.Assert;   
  25.   
  26. public class JdbcTemplatePlus extends JdbcTemplate {   
  27.   
  28.     private Connection connection=null;   
  29.     private boolean useOneConnection=false;   
  30.   
  31.     public JdbcTemplatePlus() {   
  32.         super();   
  33.     }   
  34.     public JdbcTemplatePlus(DataSource dataSource) {   
  35.         super(dataSource);   
  36.     }   
  37.     public JdbcTemplatePlus(DataSource dataSource, boolean lazyInit) {   
  38.         super(dataSource,lazyInit);   
  39.     }   
  40.        
  41.     private Connection tryGetConnection(){   
  42.         if (useOneConnection){   
  43.             if (connection==null){   
  44.                 connection= DataSourceUtils.getConnection(getDataSource());   
  45.             }   
  46.             return connection;   
  47.         }   
  48.         return DataSourceUtils.getConnection(getDataSource());   
  49.     }   
  50.        
  51.     private void tryReleaseConnection(Connection con){   
  52.         if (!useOneConnection){   
  53.             DataSourceUtils.releaseConnection(con, getDataSource());   
  54.         }   
  55.     }   
  56.        
  57.     public Connection getConnection(){   
  58.         return connection;   
  59.     }   
  60.        
  61.     public void setConnection(Connection connection){   
  62.         this.connection=connection;   
  63.     }   
  64.        
  65.     public boolean isUseOneConnection() {   
  66.         return useOneConnection;   
  67.     }   
  68.   
  69.     public void setUseOneConnection(boolean useOneConnection) {   
  70.         this.useOneConnection = useOneConnection;   
  71.     }   
  72.        
  73.     public void releaseConnection(){   
  74.         DataSourceUtils.releaseConnection(connection, getDataSource());   
  75.     }   
  76.        
  77.        
  78.     // 不明白这个方法为什么spring不把他弄成 protected 或 public,   
  79.     // 导致我要重写execute方法时还必须要重写这个方法 <img src="/images/forum/smiles/icon_sad.gif"/>   
  80.     public static String getSql(Object sqlProvider) {   
  81.         if (sqlProvider instanceof SqlProvider) {   
  82.             return ((SqlProvider) sqlProvider).getSql();   
  83.         }   
  84.         else {   
  85.             return null;   
  86.         }   
  87.     }   
  88.        
  89.     /*  
  90.         对 execute方法的修改如下:  
  91.         把所有的 this.ativeJdbcExtractor换成 getNativeJdbcExtractor(), 这个是必须的 呵呵.  
  92.           
  93.         把所有 Connection con = DataSourceUtils.getConnection(getDataSource()); 换成  
  94.         Connection con = tryGetConnection();  
  95.           
  96.         把所有 DataSourceUtils.releaseConnection(con, getDataSource());  换成  
  97.         tryReleaseConnection(con);  
  98.      */  
  99.        
  100.     public Object execute(ConnectionCallback action) throws DataAccessException {   
  101.         Assert.notNull(action, "Callback object must not be null");   
  102.   
  103.         Connection con = tryGetConnection();   
  104.         try {   
  105.             Connection conToUse = con;   
  106.             if (getNativeJdbcExtractor() != null) {   
  107.                 conToUse = getNativeJdbcExtractor().getNativeConnection(con);   
  108.             } else {   
  109.                 conToUse = createConnectionProxy(con);   
  110.             }   
  111.             return action.doInConnection(conToUse);   
  112.         } catch (SQLException ex) {   
  113.             tryReleaseConnection(con);   
  114.             con = null;   
  115.             throw getExceptionTranslator().translate("ConnectionCallback",   
  116.                     getSql(action), ex);   
  117.         } finally {   
  118.             tryReleaseConnection(con);   
  119.         }   
  120.     }   
  121.   
  122.     public Object execute(StatementCallback action) throws DataAccessException {   
  123.         Assert.notNull(action, "Callback object must not be null");   
  124.   
  125.         Connection con = tryGetConnection();   
  126.         Statement stmt = null;   
  127.         try {   
  128.             Connection conToUse = con;   
  129.             if (getNativeJdbcExtractor() != null  
  130.                     && getNativeJdbcExtractor()   
  131.                             .isNativeConnectionNecessaryForNativeStatements()) {   
  132.                 conToUse = getNativeJdbcExtractor().getNativeConnection(con);   
  133.             }   
  134.             stmt = conToUse.createStatement();   
  135.             applyStatementSettings(stmt);   
  136.             Statement stmtToUse = stmt;   
  137.             if (getNativeJdbcExtractor() != null) {   
  138.                 stmtToUse = getNativeJdbcExtractor().getNativeStatement(stmt);   
  139.             }   
  140.             Object result = action.doInStatement(stmtToUse);   
  141.             handleWarnings(stmt.getWarnings());   
  142.             return result;   
  143.         } catch (SQLException ex) {   
  144.             JdbcUtils.closeStatement(stmt);   
  145.             stmt = null;   
  146.             tryReleaseConnection(con);   
  147.             con = null;   
  148.             throw getExceptionTranslator().translate("StatementCallback",   
  149.                     getSql(action), ex);   
  150.         } finally {   
  151.             JdbcUtils.closeStatement(stmt);   
  152.             tryReleaseConnection(con);   
  153.         }   
  154.     }   
  155.   
  156.     public Object execute(PreparedStatementCreator psc,   
  157.             PreparedStatementCallback action) throws DataAccessException {   
  158.   
  159.         Assert.notNull(psc, "PreparedStatementCreator must not be null");   
  160.         Assert.notNull(action, "Callback object must not be null");   
  161.         if (logger.isDebugEnabled()) {   
  162.             String sql = getSql(psc);   
  163.             logger.debug("Executing prepared SQL statement"  
  164.                     + (sql != null ? " [" + sql + "]" : ""));   
  165.         }   
  166.   
  167.         Connection con = tryGetConnection();   
  168.         PreparedStatement ps = null;   
  169.         try {   
  170.             Connection conToUse = con;   
  171.             if (getNativeJdbcExtractor() != null  
  172.                     && getNativeJdbcExtractor()   
  173.                             .isNativeConnectionNecessaryForNativePreparedStatements()) {   
  174.                 conToUse = getNativeJdbcExtractor().getNativeConnection(con);   
  175.             }   
  176.             ps = psc.createPreparedStatement(conToUse);   
  177.             applyStatementSettings(ps);   
  178.             PreparedStatement psToUse = ps;   
  179.             if (getNativeJdbcExtractor() != null) {   
  180.                 psToUse = getNativeJdbcExtractor()   
  181.                         .getNativePreparedStatement(ps);   
  182.             }   
  183.             Object result = action.doInPreparedStatement(psToUse);   
  184.             handleWarnings(ps.getWarnings());   
  185.             return result;   
  186.         } catch (SQLException ex) {   
  187.             if (psc instanceof ParameterDisposer) {   
  188.                 ((ParameterDisposer) psc).cleanupParameters();   
  189.             }   
  190.             String sql = getSql(psc);   
  191.             psc = null;   
  192.             JdbcUtils.closeStatement(ps);   
  193.             ps = null;   
  194.             tryReleaseConnection(con);   
  195.             con = null;   
  196.             throw getExceptionTranslator().translate(   
  197.                     "PreparedStatementCallback", sql, ex);   
  198.         } finally {   
  199.             if (psc instanceof ParameterDisposer) {   
  200.                 ((ParameterDisposer) psc).cleanupParameters();   
  201.             }   
  202.             JdbcUtils.closeStatement(ps);   
  203.             tryReleaseConnection(con);   
  204.         }   
  205.     }   
  206.   
  207.     public Object execute(CallableStatementCreator csc,   
  208.             CallableStatementCallback action) throws DataAccessException {   
  209.   
  210.         Assert.notNull(csc, "CallableStatementCreator must not be null");   
  211.         Assert.notNull(action, "Callback object must not be null");   
  212.         if (logger.isDebugEnabled()) {   
  213.             String sql = getSql(csc);   
  214.             logger.debug("Calling stored procedure"  
  215.                     + (sql != null ? " [" + sql + "]" : ""));   
  216.         }   
  217.   
  218.         Connection con = tryGetConnection();   
  219.         CallableStatement cs = null;   
  220.         try {   
  221.             Connection conToUse = con;   
  222.             if (getNativeJdbcExtractor() != null) {   
  223.                 conToUse = getNativeJdbcExtractor().getNativeConnection(con);   
  224.             }   
  225.             cs = csc.createCallableStatement(conToUse);   
  226.             applyStatementSettings(cs);   
  227.             CallableStatement csToUse = cs;   
  228.             if (getNativeJdbcExtractor() != null) {   
  229.                 csToUse = getNativeJdbcExtractor()   
  230.                         .getNativeCallableStatement(cs);   
  231.             }   
  232.             Object result = action.doInCallableStatement(csToUse);   
  233.             handleWarnings(cs.getWarnings());   
  234.             return result;   
  235.         } catch (SQLException ex) {   
  236.             // Release Connection early, to avoid potential connection pool   
  237.             // deadlock   
  238.             // in the case when the exception translator hasn't been initialized   
  239.             // yet.   
  240.             if (csc instanceof ParameterDisposer) {   
  241.                 ((ParameterDisposer) csc).cleanupParameters();   
  242.             }   
  243.             String sql = getSql(csc);   
  244.             csc = null;   
  245.             JdbcUtils.closeStatement(cs);   
  246.             cs = null;   
  247.             tryReleaseConnection(con);   
  248.             con = null;   
  249.             throw getExceptionTranslator().translate(   
  250.                     "CallableStatementCallback", sql, ex);   
  251.         } finally {   
  252.             if (csc instanceof ParameterDisposer) {   
  253.                 ((ParameterDisposer) csc).cleanupParameters();   
  254.             }   
  255.             JdbcUtils.closeStatement(cs);   
  256.             tryReleaseConnection(con);   
  257.         }   
  258.     }   
  259.   
  260.     protected void finalize() throws Throwable{   
  261.         super.finalize();   
  262.         releaseConnection();   
  263.     }   
  264.   
  265.        
  266. }   

你可能感兴趣的:(DAO,spring,sql,jdbc,笑话)