老妖的博客
          現實的中沒有幾個人能夠真為對方去死,甚至山盟海誓很快就會在金錢面前變的微不足道,這才是生活。沒有永遠的愛,除了你的父母對你,當然也就沒有永遠的恨,更沒有永遠的痛,時間是最好的治療大師,它會很快撫平你心靈上累累的傷痕。很多年以后你想起來時,那些在你生命中洶涌來往的人群至多是個模糊的影子或者毫無意義的名字
          posts - 105,  comments - 171,  trackbacks - 0

          轉自:http://www.javaeye.com/topic/11190
          spring自建事務管理模塊。而且這個事務管理是一個抽象設計,可以應用到很多場合,包括普通的DataSource,jta,jms和hibernate上。

          要正確使用spring的事務,首先需要了解spring在事務設計上的一些概念
          統觀spring事務,圍繞著兩個核心PlatformTransactionManager和TransactionStatus

          PlatformTransactionManager直譯過來就是平臺相關事務,這里的平臺指的是“事務源”,包括剛才我說的DataSource,jta等等。這些無一不是一個事務源。廣義的說,凡是可以完成事務性操作的對象,都可以設計出相對應的PlatformTransactionManager,只要這個事務源支持commit,rollback和getTransaction語意。

          查看spring代碼,可以發現這些manager實現事務,就是調用事務源的事務操作方法

          比如

          HibernateTransactionManager

          代碼
          1. protected void doCommit(DefaultTransactionStatus status) {   
          2.         HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();   
          3.         if (status.isDebug()) {   
          4.             logger.debug("Committing Hibernate transaction on session [" +   
          5.                     txObject.getSessionHolder().getSession() + "]");   
          6.         }   
          7.         try {   
          8.             txObject.getSessionHolder().getTransaction().commit();   
          9.         }   
          10. ...   
          11.   
          12.     }  

           

          jdbc 的DataSourceTransactionManager

          代碼
          1. protected void doCommit(DefaultTransactionStatus status) {   
          2.         DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();   
          3.         Connection con = txObject.getConnectionHolder().getConnection();   
          4.         if (status.isDebug()) {   
          5.             logger.debug("Committing JDBC transaction on connection [" + con + "]");   
          6.         }   
          7.         try {   
          8.             con.commit();   
          9.         }   
          10.         ...   
          11.     }  

           

          那么PlatformTransactionManager以什么依據處理事務呢?
          是TransactionStatus
          查看api發現這個接口有三個方法
          isNewTransaction() ,isRollbackOnly(),setRollbackOnly()
          PlatformTransactionManager就是根據前兩個方法決定是否要創建一個新事務,是要遞交還是回滾。至于第三個方法是改變事務當前狀態的,很多地方都要用到,偏偏PlatformTransactionManager自身好像不怎么用,畢竟事務狀態的改變是由程序員代碼決定的,不需要一個manager多管閑事。

          總結上面所說的,spring的事務由PlatformTransactionManager管理,manager最后調用事務源的方法來實現一個事務過程。而manager通過TransactionStatus 來決定如何實現。

          接下去說spring事務中的TransactionTemplate和TransactionInterceptor

          TransactionTemplate其實和spring中其他的template的作用類似,起到化簡代碼的作用,不要被它那么長的名字嚇倒了,事實上這個template并不是什么非常核心的對象。如果比較學究派的,可以去看看template設計模式,在此就不再對此贅述了。
          為什么要有TransactionTemplate?先來看看如果沒有TransactionTemplate,我們的代碼該怎么寫

          先來看看spring reference中的一段代碼

          代碼
          1. DefaultTransactionDefinition def = new DefaultTransactionDefinition()   
          2. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);   
          3.   
          4. TransactionStatus status = transactionManager.getTransaction(def);   
          5.   
          6. try {   
          7.     // execute your business logic here   
          8. catch (MyException ex) {   
          9.     transactionManager.rollback(status);   
          10.     throw ex;   
          11. }   
          12. transactionManager.commit(status);  

          這是直接使用transactionManager的例子,可以看到真正執行business logic 的地方是在try當中那段,前后的代碼都是為了完成事務管理的。如果每個business logic都要寫上那么一段,我肯定是瘋了。我們翻出TransactionTemplate的代碼看看他怎么化簡了我們的代碼

           

          代碼
          1. public Object execute(TransactionCallback action) throws TransactionException {   
          2.         TransactionStatus status = this.transactionManager.getTransaction(this);   
          3.         Object result = null;   
          4.         try {   
          5.             result = action.doInTransaction(status);   
          6.         }   
          7.         catch (RuntimeException ex) {   
          8.             // transactional code threw application exception -> rollback   
          9.             rollbackOnException(status, ex);   
          10.             throw ex;   
          11.         }   
          12.         catch (Error err) {   
          13.             // transactional code threw error -> rollback   
          14.             rollbackOnException(status, err);   
          15.             throw err;   
          16.         }   
          17.         this.transactionManager.commit(status);   
          18.         return result;   
          19.     }  

           

          同上面的代碼如出一轍,前后是事務處理代碼,當中那段result = action.doInTransaction(status);是我們的應用代碼。至于action是什么,全看各位的需要了。但是有一點要主要,如果利用TransactionTemplate,那么他不管你扔出什么異常都會回滾事務,但是回滾的是哪個事務呢?繼續挖代碼

          代碼
          1. private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {   
          2.         if (logger.isDebugEnabled()) {   
          3.             logger.debug("Initiating transaction rollback on application exception", ex);   
          4.         }   
          5.         try {   
          6.             this.transactionManager.rollback(status);   
          7.         }   
          8.         catch (RuntimeException ex2) {   
          9.             logger.error("Application exception overridden by rollback exception", ex);   
          10.             throw ex2;   
          11.         }   
          12.         catch (Error err) {   
          13.             logger.error("Application exception overridden by rollback error", ex);   
          14.             throw err;   
          15.         }   
          16.     }  

          真相大白,是對template所持有的某個transactionManager進行回滾。所以如果你的應用代碼用的是事務源a的一些資源,比如到服務器a的一個datasource,但是你的transactionManager管理的是另一些資源,比如服務器b的一個datasource,代碼鐵定不會正常運行

           

          特別是在一些多事務源的程序里,這點千萬不能搞錯。如果多個事務源之間要完成全局事務,還是老老實實用分布式事務管理服務吧(jta)

          那么TransactionInterceptor是干什么的?這個是spring 的聲明式事務的支持方式。因為用TransactionTemplate要硬編碼,而且調整事務策略很麻煩(不是說不能調。舉個例子原來程序拋出異常A需要回滾,現在不需要要,我就可以把a catch吃掉。這時候template就不會回滾了。但是每次調整都要重寫編碼。)而用TransactionInterceptor就可以將這些調整寫在配置中。我們再來挖TransactionInterceptor的代碼

          代碼
          1. public Object invoke(MethodInvocation invocation) throws Throwable {   
          2.         // Work out the target class: may be null.   
          3.         // The TransactionAttributeSource should be passed the target class   
          4.         // as well as the method, which may be from an interface   
          5.         Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;   
          6.            
          7.         // Create transaction if necessary   
          8.         TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);   
          9.   
          10.         Object retVal = null;   
          11.         try {   
          12.             // This is an around advice.   
          13.             // Invoke the next interceptor in the chain.   
          14.             // This will normally result in a target object being invoked.   
          15.             retVal = invocation.proceed();   
          16.         }   
          17.         catch (Throwable ex) {   
          18.             // target invocation exception   
          19.             doCloseTransactionAfterThrowing(txInfo, ex);   
          20.             throw ex;   
          21.         }   
          22.         finally {   
          23.             doFinally(txInfo);   
          24.         }   
          25.         doCommitTransactionAfterReturning(txInfo);   
          26.   
          27.         return retVal;   
          28.     }  

          萬變不離其宗。

           

          所以使用spring的事務管理需要作這些事
          1,設置好事務源,比如DataSource,hibernate的session。如果有多個事務源要考慮他們之間是否有全局事務,如果有,老老實實用jta,否則就需要自己寫一個manager了
          2,設置manager,根據你的事務源選擇對應的PlatformTransactionManager
          3,選擇實現事物的方式,用template還是interceptor。用template代碼直觀點,但是template所管轄的manager和你應用代碼所用的事務源要一致。如果用interceptor千萬注意,一定要調用interceptor那個bean,而不是原始的那個target。在壇子上我已經看到至少有兩個朋友說spring事物不起作用,從配置和代碼上看都正確,這時要好好查查,調用的bean是哪一個。
          4,這個是設計問題了,推薦事務處于一個較高層次,比如service上的某個函數,而底層的dao可以不考慮事務,否則可能會出現事務嵌套,增加程序復雜度。

          posted on 2007-12-24 17:31 老妖 閱讀(2024) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          隨筆分類(48)

          隨筆檔案(104)

          好友鏈接

          我的豆瓣

          積分與排名

          • 積分 - 221039
          • 排名 - 257

          最新評論

          閱讀排行榜

          主站蜘蛛池模板: 义乌市| 香格里拉县| 钦州市| 三亚市| 将乐县| 临夏县| 武乡县| 灵寿县| 杂多县| 浦县| 增城市| 栖霞市| 龙游县| 竹北市| 保靖县| 寿阳县| 新安县| 紫云| 依安县| 隆昌县| 敖汉旗| 溧阳市| 临桂县| 嵩明县| 武川县| 宝清县| 舞钢市| 沙洋县| 鄯善县| 黄骅市| 鸡泽县| 北宁市| 冀州市| 大同县| 洛南县| 东莞市| 德州市| 寻甸| 仪陇县| 长子县| 色达县|