學習園地

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            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, 
          發(fā)現(xiàn)起核心是那幾個 execute 方法. 
          而那幾個execute方法的機構(gòu)大概是這樣(重點討論Connection,所以其他地方從簡) 

          Java代碼  收藏代碼
          1. execute方法開始  
          2.   
          3.   Connection con = DataSourceUtils.getConnection(getDataSource());  
          4.   
          5.   // 做一些數(shù)據(jù)庫操作  
          6.   
          7.   DataSourceUtils.releaseConnection(con, getDataSource());  
          8.   
          9. execute方法結(jié)束  


          當你要批量執(zhí)行一些操作時(不是 每個操作使用不同的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èi)部實際上執(zhí)行了,n次 getConnection,releaseConnection. 

          而這些操作,在很多時候,是可以通過一個Connection來完成的. 

          我的擴展就是實現(xiàn)了這個功能. 

          Java代碼  收藏代碼
          1. JdbcTemplatePlus jdbcTemplate=new JdbcTemplatePlus(ds);  
          2. // 內(nèi)部使用一個唯一的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. // 最后調(diào)用該方法 釋放那個內(nèi)部唯一的Connection  
          10. // 雖然我在finalize 里調(diào)用了,不過finalize畢竟不是總能在正確的時間被正確的調(diào)用  
          11. jdbcTemplate.releaseConnection();  



          我們系統(tǒng)中,有大量的嵌套查詢.使用該JdbcTemplatePlus的唯一Connection特性后,類似的操作速度提升明顯. 
          (不過可能我們原先的做法不對,也許 spring內(nèi)部已經(jīng)實現(xiàn)這個機制了 這些我就不明白了,歡迎大家來指正) 
          我們原先的做法(偽代碼): 
          Java代碼  收藏代碼
          1. public List queryNsubQueryUserList(Map param){  
          2.   
          3.     // 外層查詢  
          4.     final String bsql="select * from ......";  
          5.     final JdbcTemplate jdbcTemplate=createJdbcTemplate();  
          6.       
          7.     // 子查詢相關(guān)  
          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)后, 
          耗時變?yōu)樵鹊?/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 丘比特 閱讀(351) 評論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 淮南市| 乌拉特中旗| 秭归县| 五寨县| 怀来县| 玛纳斯县| 溆浦县| 天全县| 榆林市| 大埔县| 理塘县| 南溪县| 宣威市| 商南县| 泾川县| 屏山县| 南雄市| 宜章县| 双桥区| 拜城县| 富平县| 顺昌县| 敦化市| 阜宁县| 安西县| 沙洋县| 文化| 吴川市| 武川县| 长宁县| 静海县| 南康市| 独山县| 新绛县| 广东省| 蒲江县| 景谷| 星座| 南宫市| 高雄县| 门头沟区|