大家都知道spring支持兩種事務(wù),一種是本地連接事務(wù)(使用DataSourceTransactionManager),一種是JTA事務(wù)(使用JtaTransactionManager)。并且支持聲明式事務(wù)和編程式事務(wù)兩種方式。采用聲明式事務(wù)使用AOP方式的TransactionProxyFactoryBean代理工廠類。
                JTA事務(wù)實(shí)現(xiàn)相對(duì)較好理解,在執(zhí)行實(shí)際類的符合模式的方法時(shí),代理類通過在連接點(diǎn)前后插入預(yù)處理過程(開始事務(wù))和后處理過程(commit或rollbak)即可。因?yàn)镴TA事務(wù)支持兩階段提交所以在代碼中啟動(dòng)多少個(gè)連接(不同的connection)都能保證事務(wù)最終提交或者回滾。可是本地連接事務(wù)是如何實(shí)現(xiàn)的呢?因?yàn)楸仨毢竺娴膁ao層必須使用的同一個(gè)連接才能保證事務(wù)正常提交和回滾,在業(yè)務(wù)邏輯層可以調(diào)用dao層的多個(gè)類的多個(gè)方法,每個(gè)方法如果顯式的將connection做為參數(shù)傳入到還可以,但是這樣connection就要出現(xiàn)調(diào)用的在業(yè)務(wù)邏輯層,而且dao的每個(gè)方法還要有個(gè)connection參數(shù)比較難看,而且開發(fā)人員要關(guān)注事務(wù),這樣就沒有達(dá)到開發(fā)人員只要關(guān)注業(yè)務(wù)邏輯即可的要求。 
                web應(yīng)用,各個(gè)類都要在多線程環(huán)境下運(yùn)行,所以每個(gè)方法要保證線程安全,這樣,不在dao方法中加參數(shù)而是在dao類中加入connection屬性也就不可取了,怎么辦?查看一下JdbcTemplate類,在執(zhí)行每個(gè)方法需要數(shù)據(jù)庫連接時(shí)都使用了DataSourceUtils.getConnection(getDataSource())方法?難道每回都從數(shù)據(jù)源里面取一條連接?不可能,這樣事務(wù)肯定沒法實(shí)現(xiàn),可是怎么能保證取的是一條連接呢?對(duì)了是不是采用本地線程呀(TreadLocal),因?yàn)橐欢问聞?wù)都是在一個(gè)線程中完成,所以只要在事務(wù)開始的時(shí)候?qū)onnection存放在本地線程中,然后事務(wù)過程中從本地線程中取出connection,直到事務(wù)結(jié)束即可。不錯(cuò),這樣只需要在每個(gè)dao方法的取數(shù)據(jù)庫連接的方法中有個(gè)事務(wù)狀態(tài)的判斷即可。不錯(cuò)看看spring是不是這樣實(shí)現(xiàn)的?果然如此,DataSourceUtils.getConnection(DataSource)方法調(diào)用doGetConnection()方法,方法內(nèi)容如下:
          public static Connection doGetConnection(DataSource dataSource) throws SQLException {
            Assert.notNull(dataSource, "No DataSource specified");

            ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
            if (conHolder != null) {
             conHolder.requested();
             return conHolder.getConnection();
            }

            logger.debug("Fetching JDBC Connection from DataSource");
            Connection con = dataSource.getConnection();

            if (TransactionSynchronizationManager.isSynchronizationActive()) {
             logger.debug("Registering transaction synchronization for JDBC Connection");
             // Use same Connection for further JDBC actions within the transaction.
             // Thread-bound object will get removed by synchronization at transaction completion.
             conHolder = new ConnectionHolder(con);
             conHolder.setSynchronizedWithTransaction(true);
             conHolder.requested();
             TransactionSynchronizationManager.registerSynchronization(
               new ConnectionSynchronization(conHolder, dataSource));
             TransactionSynchronizationManager.bindResource(dataSource, conHolder);
            }

            return con;
           }
          conHolder?TransactionSynchronizationManager?很象呀,繼續(xù)看看TransactionSynchronizationManager類果真如此,里面使用TreadLocal來保存數(shù)據(jù)連接和事務(wù)狀態(tài)。原來如此,代碼里的各個(gè)層沒有特殊需要都不用再出現(xiàn)事務(wù)了,程序開發(fā)人員只要關(guān)注業(yè)務(wù)就可以了,不用再勞心編寫事務(wù)代碼了。

          Feedback

          # re: spring本地事務(wù)與JTA事務(wù)實(shí)現(xiàn)解析  回復(fù)  更多評(píng)論   

          2005-12-08 08:47 by seagoer
          不錯(cuò),我也一致疑惑 對(duì)于本地事務(wù),難道spring實(shí)現(xiàn)了自己的jta,dao層每個(gè)方法都獨(dú)自獲得連接來處理,看起來好像確實(shí)是使用本地線程來處理的。

          # re: spring本地事務(wù)與JTA事務(wù)實(shí)現(xiàn)解析  回復(fù)  更多評(píng)論   

          2006-01-11 14:17 by barry
          呵呵。我也剛剛想到這個(gè)問題。
          查看了一下spring doc。
          如果在代碼中直接使用了DataSource.getConnetction()的方式(比如遺留代碼),還可以通過設(shè)置一個(gè)TransactionAwareDataSourceProxy來代理DataSource。

          posts - 9, comments - 27, trackbacks - 0, articles - 19

          Copyright © publisher luo

          主站蜘蛛池模板: 乐亭县| 平邑县| 宁南县| 长治市| 乌兰察布市| 花莲县| 民权县| 防城港市| 安义县| 德庆县| 绵竹市| 乌拉特后旗| 郑州市| 宁化县| 永春县| 扶余县| 桃园市| 广汉市| 泌阳县| 方山县| 彭州市| 大足县| 新野县| 道真| 洛阳市| 柯坪县| 红安县| 瑞丽市| 漳浦县| 囊谦县| 马鞍山市| 普兰县| 同江市| 蒙山县| 新竹市| 巴林右旗| 丰城市| 龙口市| 文成县| 江孜县| 米林县|