隨筆-314  評(píng)論-209  文章-0  trackbacks-0
          轉(zhuǎn)自:http://www.iteye.com/topic/11738
          前幾天解釋了Spring的抽象事務(wù)機(jī)制。這次講講Spring中的DataSource 事務(wù)。
          DataSource事務(wù)相關(guān)的類比較多,我們一步步來?yè)荛_其中的密團(tuán)。

          1 如何獲得連接
          看DataSourceUtils代碼
          Java代碼 復(fù)制代碼 收藏代碼
          1. protected static Connection doGetConnection(DataSource dataSource, boolean allowSynchronization);   
          2.             throws SQLException {   
          3.            
          4.         ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;   
          5.         if (conHolder != null); {   
          6.             conHolder.requested();;   
          7.             return conHolder.getConnection();;   
          8.         }   
          9.   
          10.            
          11.         Connection con = dataSource.getConnection();;   
          12.         if (allowSynchronization && TransactionSynchronizationManager.isSynchronizationActive();); {   
          13.                         conHolder = new ConnectionHolder(con);;   
          14.             TransactionSynchronizationManager.bindResource(dataSource, conHolder);;   
          15.             TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(conHolder, dataSource););;   
          16.             conHolder.requested();;   
          17.         }   
          18.   
          19.         return con;   
          20.     }  

          原來連接是從TransactionSynchronizationManager中獲取,如果TransactionSynchronizationManager中已經(jīng)有了,那么拿過來然后調(diào)用conHolder.requested()。否則從原始的DataSource這創(chuàng)建一個(gè)連接,放到一個(gè)ConnectionHolder,然后再調(diào)用TransactionSynchronizationManager.bindResource綁定。
          好,我們又遇到兩個(gè)新的類TransactionSynchronizationManager和ConnectionHolder和。繼續(xù)跟蹤


          2 TransactionSynchronizationManager
          看其中的一些代碼
          Java代碼 復(fù)制代碼 收藏代碼
          1. private static ThreadLocal resources = new ThreadLocal();;   
          2. public static Object getResource(Object key); {   
          3.         Map map = (Map); resources.get();;   
          4.         if (map == null); {   
          5.             return null;   
          6.         }   
          7.         Object value = map.get(key);;   
          8.                 return value;   
          9.     }   
          10. public static void bindResource(Object key, Object value); throws IllegalStateException {   
          11.         Map map = (Map); resources.get();;   
          12.                 if (map == null); {   
          13.             map = new HashMap();;   
          14.             resources.set(map);;   
          15.         }   
          16.         map.put(key, value);;   
          17.             }  
          原來TransactionSynchronizationManager內(nèi)部建立了一個(gè)ThreadLocal的resources,這個(gè)resources又是和一個(gè)map聯(lián)系在一起的,這個(gè)map在某個(gè)線程第一次調(diào)用bindResource時(shí)生成。
          聯(lián)系前面的DataSourceUtils代碼,我們可以總結(jié)出來。
          某個(gè)線程使用DataSourceUtils,當(dāng)?shù)谝淮我髣?chuàng)建連接將在TransactionSynchronizationManager中創(chuàng)建出一個(gè)ThreadLocal的map。然后以DataSource作為鍵,ConnectionHolder為值放到map中。等這個(gè)線程下一次再請(qǐng)求的這個(gè)DataSource的時(shí)候,就從這個(gè)map中獲取對(duì)應(yīng)的ConnectionHolder。用map是為了解決同一個(gè)線程上多個(gè)DataSource。
          然后我們來看看ConnectionHolder又是什么?



          3 對(duì)連接進(jìn)行引用計(jì)數(shù)
          看ConnectionHolder代碼,這個(gè)類很簡(jiǎn)單,看不出個(gè)所以然,只好再去看父類代碼ResourceHolderSupport,我們感興趣的是這兩個(gè)方法
          Java代碼 復(fù)制代碼 收藏代碼
          1. public void requested(); {   
          2.         this.referenceCount++;   
          3.     }   
          4.   
          5.     public void released(); {   
          6.         this.referenceCount--;   
          7.     }  

          看得出這是一個(gè)引用計(jì)數(shù)的技巧。原來Spring中對(duì)Connection是竟量使用已創(chuàng)建的對(duì)象,而不是每次都創(chuàng)建一個(gè)新對(duì)象。這就是DataSourceUtils中
          Java代碼 復(fù)制代碼 收藏代碼
          1. if (conHolder != null); {   
          2.             conHolder.requested();;   
          3.             return conHolder.getConnection();;   
          4.         }  
          的原因


          4 釋放連接
          完成事物后DataSourceTransactionManager有這樣的代碼
          Java代碼 復(fù)制代碼 收藏代碼
          1. protected void doCleanupAfterCompletion(Object transaction); {   
          2.         DataSourceTransactionObject txObject = (DataSourceTransactionObject); transaction;   
          3.   
          4.         // Remove the connection holder from the thread.   
          5.         TransactionSynchronizationManager.unbindResource(this.dataSource);;   
          6.         txObject.getConnectionHolder();.clear();;   
          7.   
          8.         //...       DataSourceUtils.closeConnectionIfNecessary(con, this.dataSource);;   
          9.     }  

          DataSourceUtils
          Java代碼 復(fù)制代碼 收藏代碼
          1. protected static void doCloseConnectionIfNecessary(Connection con, DataSource dataSource); throws SQLException {   
          2.         if (con == null); {   
          3.             return;   
          4.         }   
          5.   
          6.         ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;   
          7.         if (conHolder != null && con == conHolder.getConnection();); {   
          8.             // It's the transactional Connection: Don't close it.   
          9.             conHolder.released();;   
          10.             return;   
          11.         }   
          12.            
          13.         // Leave the Connection open only if the DataSource is our   
          14.         // special data source, and it wants the Connection left open.   
          15.         if (!(dataSource instanceof SmartDataSource); || ((SmartDataSource); dataSource);.shouldClose(con);); {   
          16.             logger.debug("Closing JDBC connection");;   
          17.             con.close();;   
          18.         }   
          19.     }  

          恍然大悟。如果事物完成,那么就
          TransactionSynchronizationManager.unbindResource(this.dataSource);將當(dāng)前的ConnectionHolder
          從TransactionSynchronizationManager上脫離,然后doCloseConnectionIfNecessary。最后會(huì)把連接關(guān)閉掉。

          5 兩個(gè)輔助類JdbcTemplate和TransactionAwareDataSourceProxy
          JdbcTemplate中的execute方法的第一句和最后一句
          Java代碼 復(fù)制代碼 收藏代碼
          1. public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action);   
          2.             throws DataAccessException {   
          3.   
          4.         Connection con = DataSourceUtils.getConnection(getDataSource(););;   
          5.         //其他代碼   
          6.     DataSourceUtils.closeConnectionIfNecessary(con, getDataSource(););;   
          7.         }   
          8.     }  

          作用不言自明了吧

          從TransactionAwareDataSourceProxy中獲取的連接是這個(gè)樣子的
          Java代碼 復(fù)制代碼 收藏代碼
          1. public Connection getConnection(); throws SQLException {   
          2.         Connection con = DataSourceUtils.doGetConnection(getTargetDataSource();, true);;   
          3.         return getTransactionAwareConnectionProxy(con, getTargetDataSource(););;   
          4.     }  

          萬變不離其宗,不過我們還是看看getTransactionAwareConnectionProxy
          Java代碼 復(fù)制代碼 收藏代碼
          1. protected Connection getTransactionAwareConnectionProxy(Connection target, DataSource dataSource); {   
          2.         return (Connection); Proxy.newProxyInstance(   
          3.                 ConnectionProxy.class.getClassLoader();,   
          4.                 new Class[] {ConnectionProxy.class},   
          5.                 new TransactionAwareInvocationHandler(target, dataSource););;   
          6.     }  

          原來返回的是jdk的動(dòng)態(tài)代理。繼續(xù)看TransactionAwareInvocationHandler
          Java代碼 復(fù)制代碼 收藏代碼
          1. public Object invoke(Object proxy, Method method, Object[] args); throws Throwable {   
          2.         //...           if (method.getName();.equals(CONNECTION_CLOSE_METHOD_NAME);); {   
          3.                 if (this.dataSource != null); {   
          4.                     DataSourceUtils.doCloseConnectionIfNecessary(this.target, this.dataSource);;   
          5.                 }   
          6.                 return null;   
          7.             }   
          8.   
          9.                     }  

          TransactionAwareDataSourceProxy會(huì)先從DataSourceUtils獲取連接。然后將這個(gè)連接用jdk的動(dòng)態(tài)代理包一下返回。外部代碼如果調(diào)用的這個(gè)冒牌的Connection,就會(huì)先調(diào)用TransactionAwareInvocationHandler的invoke,在這個(gè)invoke 中,完成原來調(diào)用DataSourceUtils的功能。

          總結(jié)上面的流程
          Spring 對(duì)DataSource進(jìn)行事務(wù)管理的關(guān)鍵在于ConnectionHolder和TransactionSynchronizationManager。
            0.先從TransactionSynchronizationManager中嘗試獲取連接
            1.如果前一步失敗則在每個(gè)線程上,對(duì)每個(gè)DataSouce只創(chuàng)建一個(gè)Connection
             2.這個(gè)Connection用ConnectionHolder包裝起來,由TransactionSynchronizationManager管理
            3.再次請(qǐng)求同一個(gè)連接的時(shí)候,從TransactionSynchronizationManager返回已經(jīng)創(chuàng)建的ConnectionHolder,然后調(diào)用ConnectionHolder的request將引用計(jì)數(shù)+1
            4.釋放連接時(shí)要調(diào)用ConnectionHolder的released,將引用計(jì)數(shù)-1
            5.當(dāng)事物完成后,將ConnectionHolder從TransactionSynchronizationManager中解除。當(dāng)誰都不用,這個(gè)連接被close

          以上所有都是可以調(diào)用DataSourceUtils化簡(jiǎn)代碼,而JdbcTemplate又是調(diào)用DataSourceUtils的。所以在Spring文檔中要求盡量首先使用JdbcTemplate,其次是用DataSourceUtils來獲取和釋放連接。至于TransactionAwareDataSourceProxy,那是下策的下策。不過可以將Spring事務(wù)管理和遺留代碼無縫集成。

          所以如某位朋友說要使用Spring的事務(wù)管理,但是又不想用JdbcTemplate,那么可以考慮TransactionAwareDataSourceProxy。這個(gè)類是原來DataSource的代理。
          其次,想使用Spring事物,又不想對(duì)Spring進(jìn)行依賴是不可能的。與其試圖自己模擬DataSourceUtils,不如直接使用現(xiàn)成的。
          posted on 2011-08-09 14:59 xzc 閱讀(4012) 評(píng)論(1)  編輯  收藏 所屬分類: Spring

          評(píng)論:
          # re: Spring事務(wù)管理與數(shù)據(jù)庫(kù)連接 2014-06-18 22:52 | zuidaima
          主站蜘蛛池模板: 黄浦区| 柳江县| 惠水县| 建宁县| 江门市| 九龙城区| 屏山县| 江西省| 咸阳市| 襄汾县| 永靖县| 高平市| 高青县| 涟源市| 洱源县| 得荣县| 邻水| 枝江市| 渑池县| 新密市| 恩平市| 金山区| 南宫市| 马边| 尼玛县| 内乡县| 平谷区| 贡嘎县| 永康市| 阿荣旗| 吴忠市| 五莲县| 湟中县| 尤溪县| 阳东县| 莎车县| 镶黄旗| 福安市| 临清市| 莒南县| 阿坝县|