Spring事務:一種編程式事務,三種聲明式事務


事務隔離級別

隔離級別是指若干個並發的事務之間的隔離程度。TransactionDefinition 接口中定義了五個表示隔離級別的常量:

  • TransactionDefinition.ISOLATION_DEFAULT:這是默認值,表示使用底層數據庫的默認隔離級別。對大部分數據庫而言,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。該級別不能防止臟讀和不可重復讀,因此很少使用該隔離級別。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止臟讀,這也是大多數情況下的推薦值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級別表示一個事務在整個過程中可以多次重復執行某個查詢,並且每次返回的記錄都相同。即使在多次查詢之間有新增的數據滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止臟讀和不可重復讀。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。

事務傳播行為

所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。在TransactionDefinition定義中包括了如下幾個表示傳播行為的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,如果當前存在事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。

這里需要指出的是,前面的六種事務傳播行為是 Spring 從 EJB 中引入的,他們共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 啟動的事務內嵌於外部事務中(如果存在外部事務的話),此時,內嵌事務並不是一個獨立的事務,它依賴於外部事務的存在,只有通過外部的事務提交,才能引起內部事務的提交,嵌套的子事務不能單獨提交。如果熟悉 JDBC 中的保存點(SavePoint)的概念,那嵌套事務就很容易理解了,其實嵌套的子事務就是保存點的一個應用,一個事務中可以包括多個保存點,每一個嵌套子事務。另外,外部事務的回滾也會導致嵌套子事務的回滾。

事務超時

所謂事務超時,就是指一個事務所允許執行的最長時間,如果超過該時間限制但事務還沒有完成,則自動回滾事務。在 TransactionDefinition 中以 int 的值來表示超時時間,其單位是秒。

事務的只讀屬性

事務的只讀屬性是指,對事務性資源進行只讀操作或者是讀寫操作。所謂事務性資源就是指那些被事務管理的資源,比如數據源、 JMS 資源,以及自定義的事務性資源等等。如果確定只對事務性資源進行只讀操作,那么我們可以將事務標志為只讀的,以提高事務處理的性能。在 TransactionDefinition 中以 boolean 類型來表示該事務是否只讀。

事務的回滾規則

通常情況下,如果在事務中拋出了未檢查異常(繼承自 RuntimeException 的異常),則默認將回滾事務。如果沒有拋出任何異常,或者拋出了已檢查異常,則仍然提交事務。這通常也是大多數開發者希望的處理方式,也是 EJB 中的默認處理方式。但是,我們可以根據需要人為控制事務在拋出某些未檢查異常時任然提交事務,或者在拋出某些已檢查異常時回滾事務。

聲明式事務:可知編程式事務每次實現都要單獨實現,但業務量大功能復雜時,使用編程式事務無疑是痛苦的,而聲明式事務不同,聲明式事務屬於無侵入式,不會影響業務邏輯的實現。

聲明式事務實現方式主要有3種,一種為基於AOP方式的聲明式事務【基於TransactionProxyFactoryBean】,一種為基於AspectJ的聲明式事務【一種為通過使用Spring的<tx:advice>定義事務通知與AOP相關配置實現】,另為一種通過@Transactional注解實現事務管理實現,下面詳細說明2種方法如何配置,已經相關注意點

1)方式一,配置文件如下
<!-- 
<tx:advice>定義事務通知,用於指定事務屬性,其中“transaction-manager”屬性指定事務管理器,並通過<tx:attributes>指定具體需要攔截的方法
    <tx:method>攔截方法,其中參數有:
    name:方法名稱,將匹配的方法注入事務管理,可用通配符
    propagation:事務傳播行為,
    isolation:事務隔離級別定義;默認為“DEFAULT”
    timeout:事務超時時間設置,單位為秒,默認-1,表示事務超時將依賴於底層事務系統;
    read-only:事務只讀設置,默認為false,表示不是只讀;
    rollback-for:需要觸發回滾的異常定義,可定義多個,以“,”分割,默認任何RuntimeException都將導致事務回滾,而任何Checked Exception將不導致事務回滾;
    no-rollback-for:不被觸發進行回滾的 Exception(s);可定義多個,以“,”分割;
 -->
<tx:advice id="advice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 攔截save開頭的方法,事務傳播行為為:REQUIRED:必須要有事務, 如果沒有就在上下文創建一個 -->
        <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="" read-only="false" no-rollback-for="" rollback-for=""/>
        <!-- 支持,如果有就有,沒有就沒有 -->
        <tx:method name="*" propagation="SUPPORTS"/>
    </tx:attributes>
</tx:advice>
<!-- 定義切入點,expression為切人點表達式,如下是指定impl包下的所有方法,具體以自身實際要求自定義  -->
<aop:config>
    <aop:pointcut expression="execution(* com.kaizhi.*.service.impl.*.*(..))" id="pointcut"/>
    <!--<aop:advisor>定義切入點,與通知,把tx與aop的配置關聯,才是完整的聲明事務配置 -->
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>
注意點:
  1. 事務回滾異常只能為RuntimeException異常,而Checked Exception異常不回滾,捕獲異常不拋出也不會回滾,但可以強制事務回滾:TransactionAspectSupport.currentTransactionStatus().isRollbackOnly();
  2. 解決“自我調用”而導致的不能設置正確的事務屬性問題,可參考http://www.iteye.com/topic/1122740

2)方式二通過@Transactional實現事務管理

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
     <property name="dataSource" ref="dataSource"/>
</bean>    
<tx:annotation-driven transaction-manager="txManager"/> //開啟事務注解
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED),具體參數跟上面<tx:method>中一樣
Spring提供的@Transaction注解事務管理,內部同樣是利用環繞通知TransactionInterceptor實現事務的開啟及關閉。

使用@Transactional注意點:
    1. 如果在接口、實現類或方法上都指定了@Transactional 注解,則優先級順序為方法>實現類>接口;
    2. 建議只在實現類或實現類的方法上使用@Transactional,而不要在接口上使用,這是因為如果使用JDK代理機制(基於接口的代理)是沒問題;而使用使用CGLIB代理(繼承)機制時就會遇到問題,因為其使用基於類的代理而不是接口,這是因為接口上的@Transactional注解是“不能繼承的”;

3.注意事項

* 如果配置了聲明式事務,在出現運行時異常時,事務會回滾,但是出現非運行時異常時,事務不回滾。

* 如果配置了編程式事務,則不管出現什么異常,事務都會回滾。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM