posts - 64,  comments - 9,  trackbacks - 0

          首先,我們配置了一個(gè) TransactionInterceptor 來定義相關(guān)的事務(wù)規(guī)則,他有兩個(gè)主要的屬性:一個(gè)是 transactionManager,用來指定一個(gè)事務(wù)管理器,并將具體事務(wù)相關(guān)的操作委托給它;另一個(gè)是 Properties 類型的 transactionAttributes 屬性,它主要用來定義事務(wù)規(guī)則,該屬性的每一個(gè)鍵值對(duì)中,鍵指定的是方法名,方法名可以使用通配符,而值就表示相應(yīng)方法的所應(yīng)用的事務(wù)屬性。

            指定事務(wù)屬性的取值有較復(fù)雜的規(guī)則,這在 Spring 中算得上是一件讓人頭疼的事。具體的書寫規(guī)則如下:

          傳播行為 [,隔離級(jí)別] [,只讀屬性] [,超時(shí)屬性] [不影響提交的異常] [,導(dǎo)致回滾的異常]

            傳播行為是唯一必須設(shè)置的屬性,其他都可以忽略,Spring為我們提供了合理的默認(rèn)值。

            傳播行為的取值必須以“PROPAGATION_”開頭,具體包括:PROPAGATION_MANDATORY、 PROPAGATION_NESTED、PROPAGATION_NEVER、PROPAGATION_NOT_SUPPORTED、 PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_SUPPORTS,共七種取值。

            隔離級(jí)別的取值必須以“ISOLATION_”開頭,具體包括:ISOLATION_DEFAULT、 ISOLATION_READ_COMMITTED、ISOLATION_READ_UNCOMMITTED、 ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE,共五種取值。

            如果事務(wù)是只讀的,那么我們可以指定只讀屬性,使用“readOnly”指定。否則我們不需要設(shè)置該屬性。

            超時(shí)屬性的取值必須以“TIMEOUT_”開頭,后面跟一個(gè)int類型的值,表示超時(shí)時(shí)間,單位是秒。

            不影響提交的異常是指,即使事務(wù)中拋出了這些類型的異常,事務(wù)任然正常提交。必須在每一個(gè)異常的名字前面加上“+”。異常的名字可以是類名的一部分。比如“+RuntimeException”、“+tion”等等。

          導(dǎo)致回滾的異常是指,當(dāng)事務(wù)中拋出這些類型的異常時(shí),事務(wù)將回滾。必須在每一個(gè)異常的名字前面加上“-”。異常的名字可以是類名的全部或者部分,比如“-RuntimeException”、“-tion”等等。

            以下是兩個(gè)示例:

          <property name="*Service">
          PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,TIMEOUT_20,
          +AbcException,+DefException,-HijException
          </property>

          以上表達(dá)式表示,針對(duì)所有方法名以 Service 結(jié)尾的方法,使用 PROPAGATION_REQUIRED 事務(wù)傳播行為,事務(wù)的隔離級(jí)別是 ISOLATION_READ_COMMITTED,超時(shí)時(shí)間為20秒,當(dāng)事務(wù)拋出 AbcException 或者 DefException 類型的異常,則仍然提交,當(dāng)拋出 HijException 類型的異常時(shí)必須回滾事務(wù)。這里沒有指定"readOnly",表示事務(wù)不是只讀的。

          <property name="test">PROPAGATION_REQUIRED,readOnly</property>

          以上表達(dá)式表示,針對(duì)所有方法名為 test 的方法,使用 PROPAGATION_REQUIRED 事務(wù)傳播行為,并且該事務(wù)是只讀的。除此之外,其他的屬性均使用默認(rèn)值。比如,隔離級(jí)別和超時(shí)時(shí)間使用底層事務(wù)性資源的默認(rèn)值,并且當(dāng)發(fā)生未檢查異常,則回滾事務(wù),發(fā)生已檢查異常則仍提交事務(wù)。

          配置好了 TransactionInterceptor,我們還需要配置一個(gè) ProxyFactoryBean 來組裝 target 和advice。這也是典型的 Spring AOP 的做法。通過 ProxyFactoryBean 生成的代理類就是織入了事務(wù)管理邏輯后的目標(biāo)類。至此,聲明式事務(wù)管理就算是實(shí)現(xiàn)了。我們沒有對(duì)業(yè)務(wù)代碼進(jìn)行任何操作,所有設(shè)置均在配置文件中完成,這就是聲明式事務(wù)的最大優(yōu)點(diǎn)。

          基于 TransactionProxy... 的聲明式事務(wù)管理

          前面的聲明式事務(wù)雖然好,但是卻存在一個(gè)非常惱人的問題:配置文件太多。我們必須針對(duì)每一個(gè)目標(biāo)對(duì)象配置一個(gè) ProxyFactoryBean;另外,雖然可以通過父子 Bean 的方式來復(fù)用 TransactionInterceptor 的配置,但是實(shí)際的復(fù)用幾率也不高;這樣,加上目標(biāo)對(duì)象本身,每一個(gè)業(yè)務(wù)類可能需要對(duì)應(yīng)三個(gè) <bean/> 配置,隨著業(yè)務(wù)類的增多,配置文件將會(huì)變得越來越龐大,管理配置文件又成了問題。

            為了緩解這個(gè)問題,Spring 為我們提供了 TransactionProxyFactoryBean,用于將TransactionInterceptor 和 ProxyFactoryBean 的配置合二為一。如清單9所示:

            清單9. 基于 TransactionProxyFactoryBean 的事務(wù)管理示例配置文件

          <beans......>
          ......
          <bean id="bankServiceTarget"
          class="footmark.spring.core.tx.declare.classic.BankServiceImpl">
          <property name="bankDao" ref="bankDao"/>
          </bean>
          <bean id="bankService"
          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
          <property name="target" ref="bankServiceTarget"/>
          <property name="transactionManager" ref="transactionManager"/>
          <property name="transactionAttributes">
          <props>
          <prop key="transfer">PROPAGATION_REQUIRED</prop>
          </props>
          </property>
          </bean>
          ......
          </beans>

          如此一來,配置文件與先前相比簡化了很多。我們把這種配置方式稱為 Spring 經(jīng)典的聲明式事務(wù)管理。相信在早期使用 Spring 的開發(fā)人員對(duì)這種配置聲明式事務(wù)的方式一定非常熟悉。

          但是,顯式為每一個(gè)業(yè)務(wù)類配置一個(gè) TransactionProxyFactoryBean 的做法將使得代碼顯得過于刻板,為此我們可以使用自動(dòng)創(chuàng)建代理的方式來將其簡化,使用自動(dòng)創(chuàng)建代理是純 AOP 知識(shí),請(qǐng)讀者參考相關(guān)文檔,不在此贅述。

            基于 <tx> 命名空間的聲明式事務(wù)管理

          前面兩種聲明式事務(wù)配置方式奠定了 Spring 聲明式事務(wù)管理的基石。在此基礎(chǔ)上,Spring 2.x 引入了 <tx> 命名空間,結(jié)合使用 <aop> 命名空間,帶給開發(fā)人員配置聲明式事務(wù)的全新體驗(yàn),配置變得更加簡單和靈活。另外,得益于 <aop> 命名空間的切點(diǎn)表達(dá)式支持,聲明式事務(wù)也變得更加強(qiáng)大。

            如清單10所示:

            清單10. 基于 <tx> 的事務(wù)管理示例配置文件

          <beans......>
          ......
          <bean id="bankService"
          class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
          <property name="bankDao" ref="bankDao"/>
          </bean>
          <tx:advice id="bankAdvice" transaction-manager="transactionManager">
          <tx:attributes>
          <tx:method name="transfer" propagation="REQUIRED"/>
          </tx:attributes>
          </tx:advice>
          <aop:config>
          <aop:pointcut id="bankPointcut" expression="execution(* *.transfer(..))"/>
          <aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
          </aop:config>
          ......
          </beans>

          如果默認(rèn)的事務(wù)屬性就能滿足要求,那么代碼簡化為如清單 11 所示:

            清單 11. 簡化后的基于 <tx> 的事務(wù)管理示例配置文件

          <beans......>
          ......
          <bean id="bankService"
          class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
          <property name="bankDao" ref="bankDao"/>
          </bean>
          <tx:advice id="bankAdvice" transaction-manager="transactionManager">
          <aop:config>
          <aop:pointcut id="bankPointcut" expression="execution(**.transfer(..))"/>
          <aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
          </aop:config>
          ......
          </beans>

          由于使用了切點(diǎn)表達(dá)式,我們就不需要針對(duì)每一個(gè)業(yè)務(wù)類創(chuàng)建一個(gè)代理對(duì)象了。另外,如果配置的事務(wù)管理器 Bean 的名字取值為“transactionManager”,則我們可以省略 <tx:advice> 的 transaction-manager 屬性,因?yàn)樵搶傩缘哪J(rèn)值即為“transactionManager”。

            基于 @Transactional 的聲明式事務(wù)管理

            除了基于命名空間的事務(wù)配置方式,Spring 2.x 還引入了基于 Annotation 的方式,具體主要涉及@Transactional 標(biāo)注。@Transactional 可以作用于接口、接口方法、類以及類方法上。當(dāng)作用于類上時(shí),該類的所有 public 方法將都具有該類型的事務(wù)屬性,同時(shí),我們也可以在方法級(jí)別使用該標(biāo)注來覆蓋類級(jí)別的定義。如清單12所示:

          清單12. 基于 @Transactional 的事務(wù)管理示例配置文件

          @Transactional(propagation = Propagation.REQUIRED)
          public boolean transfer(Long fromId, Long toId, double amount) {
          return bankDao.transfer(fromId, toId, amount);
          }

            Spring 使用 BeanPostProcessor 來處理 Bean 中的標(biāo)注,因此我們需要在配置文件中作如下聲明來激活該后處理 Bean,如清單13所示:

            清單13. 啟用后處理Bean的配置

          <tx:annotation-driven transaction-manager="transactionManager"/>

            與前面相似,transaction-manager 屬性的默認(rèn)值是 transactionManager,如果事務(wù)管理器 Bean 的名字即為該值,則可以省略該屬性。

          雖然 @Transactional 注解可以作用于接口、接口方法、類以及類方法上,但是 Spring 小組建議不要在接口或者接口方法上使用該注解,因?yàn)檫@只有在使用基于接口的代理時(shí)它才會(huì)生效。另外, @Transactional 注解應(yīng)該只被應(yīng)用到 public 方法上,這是由 Spring AOP 的本質(zhì)決定的。如果你在 protected、private 或者默認(rèn)可見性的方法上使用 @Transactional 注解,這將被忽略,也不會(huì)拋出任何異常。

          基于 <tx> 命名空間和基于 @Transactional 的事務(wù)聲明方式各有優(yōu)缺點(diǎn)?;?<tx> 的方式,其優(yōu)點(diǎn)是與切點(diǎn)表達(dá)式結(jié)合,功能強(qiáng)大。利用切點(diǎn)表達(dá)式,一個(gè)配置可以匹配多個(gè)方法,而基于 @Transactional 的方式必須在每一個(gè)需要使用事務(wù)的方法或者類上用 @Transactional 標(biāo)注,盡管可能大多數(shù)事務(wù)的規(guī)則是一致的,但是對(duì) @Transactional 而言,也無法重用,必須逐個(gè)指定。另一方面,基于 @Transactional 的方式使用起來非常簡單明了,沒有學(xué)習(xí)成本。開發(fā)人員可以根據(jù)需要,任選其中一種使用,甚至也可以根據(jù)需要混合使用這兩種方式。

          如果不是對(duì)遺留代碼進(jìn)行維護(hù),則不建議再使用基于 TransactionInterceptor 以及基于TransactionProxyFactoryBean 的聲明式事務(wù)管理方式,但是,學(xué)習(xí)這兩種方式非常有利于對(duì)底層實(shí)現(xiàn)的理解。

          雖然上面共列舉了四種聲明式事務(wù)管理方式,但是這樣的劃分只是為了便于理解,其實(shí)后臺(tái)的實(shí)現(xiàn)方式是一樣的,只是用戶使用的方式不同而已。

            結(jié)束語

            本教程的知識(shí)點(diǎn)大致總結(jié)如下:

            基于 TransactionDefinition、PlatformTransactionManager、TransactionStatus 編程式事務(wù)管理是 Spring 提供的最原始的方式,通常我們不會(huì)這么寫,但是了解這種方式對(duì)理解 Spring 事務(wù)管理的本質(zhì)有很大作用。

            基于 TransactionTemplate 的編程式事務(wù)管理是對(duì)上一種方式的封裝,使得編碼更簡單、清晰。

            基于 TransactionInterceptor 的聲明式事務(wù)是 Spring 聲明式事務(wù)的基礎(chǔ),通常也不建議使用這種方式,但是與前面一樣,了解這種方式對(duì)理解 Spring 聲明式事務(wù)有很大作用。

            基于 TransactionProxyFactoryBean 的聲明式事務(wù)是上中方式的改進(jìn)版本,簡化的配置文件的書寫,這是 Spring 早期推薦的聲明式事務(wù)管理方式,但是在 Spring 2.0 中已經(jīng)不推薦了。

            基于 <tx> 和 <aop> 命名空間的聲明式事務(wù)管理是目前推薦的方式,其最大特點(diǎn)是與 Spring AOP 結(jié)合緊密,可以充分利用切點(diǎn)表達(dá)式的強(qiáng)大支持,使得管理事務(wù)更加靈活。

            基于 @Transactional 的方式將聲明式事務(wù)管理簡化到了極致。開發(fā)人員只需在配置文件中加上一行啟用相關(guān)后處理 Bean 的配置,然后在需要實(shí)施事務(wù)管理的方法或者類上使用 @Transactional 指定事務(wù)規(guī)則即可實(shí)現(xiàn)事務(wù)管理,而且功能也不必其他方式遜色
          posted on 2009-09-04 16:27 super_nini 閱讀(1637) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2009年9月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          常用鏈接

          留言簿

          隨筆檔案

          文章檔案

          相冊(cè)

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 北辰区| 东乡县| 拜泉县| 祁阳县| 商南县| 进贤县| 织金县| 义马市| 华阴市| 平顺县| 修武县| 华蓥市| 布拖县| 皮山县| 乌什县| 大关县| 临高县| 湘潭县| 梧州市| 安乡县| 山东省| 肇源县| 商南县| 沅江市| 介休市| 云浮市| 忻州市| 安西县| 阳东县| 鄂托克旗| 印江| 大埔县| 霸州市| 临颍县| 柞水县| 渭源县| 抚宁县| 克山县| 泉州市| 丰城市| 浦江县|