学习园地

BlogJava 首页 新随笔 联系 聚合 管理
  3 Posts :: 14 Stories :: 0 Comments :: 0 Trackbacks
对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,所以其他地方从简) 

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


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

如下: 
Java代码  收藏代码
  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. ......  


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

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

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

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



我们系统中,有大量的嵌套查询.使用该JdbcTemplatePlus的唯一Connection特性后,类似的操作速度提升明显. 
(不过可能我们原先的做法不对,也许 spring内部已经实现这个机制了 这些我就不明白了,欢迎大家来指正) 
我们原先的做法(伪代码): 
Java代码  收藏代码
  1. public List queryNsubQueryUserList(Map param){  
  2.   
  3.     // 外层查询  
  4.     final String bsql="select * from ......";  
  5.     final JdbcTemplate jdbcTemplate=createJdbcTemplate();  
  6.       
  7.     // 子查询相关  
  8.     final String subSql="select ............ ";  
  9.     final JdbcTemplate subJdbcTemplate=createJdbcTemplate();  
  10.       
  11.     List rslist=jdbcTemplate.query(bsql.toString(),sqlArg,   
  12.         new ResultSetHandler(){  
  13.             public void processRow(ResultSet rs) throws SQLException {  
  14.                 final 一个VO recordObj=new 一个VO();  
  15.                 // 子查询  
  16.                 subJdbcTemplate.query(subSql, subQueryArgs,   
  17.                     new ResultSetHandler(){  
  18.                         public void processRow(ResultSet rs) throws SQLException {  
  19.                             // 一些操作........  
  20.                         }  
  21.                     }  
  22.                 );  
  23.                     // 一些操作........  
  24.                     recordObj.setXXXXX(rs.getString("XXXXX"));  
  25.                     .........  
  26.                     // 将记录放入集合  
  27.                     addRecord(recordObj);  
  28.             }  
  29.         }  
  30.     );  
  31.     return rslist;  
  32.     }  
  33. }  

在使用 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); 

Java代码  收藏代码
  1. package com.neusoft.tdframework.dao;  
  2.   
  3. import java.sql.CallableStatement;  
  4. import java.sql.Connection;  
  5. import java.sql.PreparedStatement;  
  6. import java.sql.SQLException;  
  7. import java.sql.Statement;  
  8.   
  9. import javax.sql.DataSource;  
  10.   
  11. import org.springframework.dao.DataAccessException;  
  12. import org.springframework.jdbc.core.CallableStatementCallback;  
  13. import org.springframework.jdbc.core.CallableStatementCreator;  
  14. import org.springframework.jdbc.core.ConnectionCallback;  
  15. import org.springframework.jdbc.core.JdbcTemplate;  
  16. import org.springframework.jdbc.core.ParameterDisposer;  
  17. import org.springframework.jdbc.core.PreparedStatementCallback;  
  18. import org.springframework.jdbc.core.PreparedStatementCreator;  
  19. import org.springframework.jdbc.core.SqlProvider;  
  20. import org.springframework.jdbc.core.StatementCallback;  
  21. import org.springframework.jdbc.datasource.DataSourceUtils;  
  22. import org.springframework.jdbc.support.JdbcUtils;  
  23. import org.springframework.util.Assert;  
  24.   
  25. public class JdbcTemplatePlus extends JdbcTemplate {  
  26.   
  27.     private Connection connection=null;  
  28.     private boolean useOneConnection=false;  
  29.   
  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方法时还必须要重写这个方法  :(  
  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.   
  261.     protected void finalize() throws Throwable{  
  262.         super.finalize();  
  263.         releaseConnection();  
  264.     }  
  265.   
  266.   
  267.       
  268. }  
posted on 2014-03-26 22:45 丘比特 阅读(309) 评论(0)  编辑  收藏 所属分类: Java

只有注册用户登录后才能发表评论。


网站导航: