天天看點

學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明

Spring Java 事務原理與應用

事務控制有兩種,一種是配置相應的方法,一種是通過注解@Transaction,可以在配置檔案中都配置也可以有選擇的配置。

資料表需要時InnoDB

       一、什麼是Java事務

    事務必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一緻性(consistency)、隔離性 (isolation)和持久性(durability)的縮寫。事務的原子性表示事務執行過程中的任何失敗都将導緻事務所做的任何修改失效。一緻性表示 當事務執行失敗時,所有被該事務影響的資料都應該恢複到事務執行前的狀态。隔離性表示在事務執行過程中對資料的修改,在事務送出之前對其他事務不可見。持久性表示已送出的資料在事務執行失敗時,資料的狀态都應該正确。

      二、為什麼需要Java事務

    事務是為解決資料安全操作提出的,事務控制實際上就是控制資料的安全通路。舉一個簡單例子:比如銀行轉帳業務,賬戶A要将自己賬戶上的1000元轉到B賬 戶下面,A賬戶餘額首先要減去1000元,然後B賬戶要增加1000元。假如在中間網絡出現了問題,A賬戶減去1000元已經結束,B因為網絡中斷而操作 失敗,那麼整個業務失敗,必須做出控制,要求A賬戶轉帳業務撤銷。這才能保證業務的正确性,完成這個操作就需要事務,将A賬戶資金減少和B賬戶資金增加方 到一個事務裡面,要麼全部執行成功,要麼操作全部撤銷,這樣就保持了資料的安全性。

     三、Java事務的類型

    Java事務的類型有三種:JDBC事務、JTA(Java Transaction API)事務、容器事務。

     1、JDBC事務

    JDBC 事務是用 Connection 對象控制的。JDBC Connection 接口( java.sql.Connection )提供了兩種事務模式:自動送出和手工送出。 java.sql.Connection 提供了以下控制事務的方法:

public void setAutoCommit(boolean)

public boolean getAutoCommit()

public void commit()

public void rollback()

    使用 JDBC 事務界定時,您可以将多個 SQL 語句結合到一個事務中。JDBC 事務的一個缺點是事務的範圍局限于一個資料庫連接配接。一個 JDBC 事務不能跨越多個資料庫。

      2、JTA(Java Transaction API)事務

    JTA是一種高層的,與實作無關的,與協定無關的API,應用程式和應用伺服器可以使用JTA來通路事務。

    JTA允許應用程式執行分布式事務處理——在兩個或多個網絡計算機資源上通路并且更新資料,這些資料可以分布在多個資料庫上。JDBC驅動程式的JTA支援極大地增強了資料通路能力。

    如果計劃用 JTA 界定事務,那麼就需要有一個實作 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驅動程式。一個實作了這些接口的驅動程式将可以參與 JTA 事務。一個 XADataSource 對象就是一個 XAConnection 對象的工廠。 XAConnection s 是參與 JTA 事務的 JDBC 連接配接。

    您将需要用應用伺服器的管理工具設定 XADataSource .從應用伺服器和 JDBC 驅動程式的文檔中可以了解到相關的指導。

     J2EE應用程式用 JNDI 查詢資料源。一旦應用程式找到了資料源對象,它就調用 javax.sql.DataSource.getConnection() 以獲得到資料庫的連接配接。

    XA 連接配接與非 XA 連接配接不同。一定要記住 XA 連接配接參與了 JTA 事務。這意味着 XA 連接配接不支援 JDBC 的自動送出功能。同時,應用程式一定不要對 XA 連接配接調用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() .(這些是自動送出的)

    相反,應用程式應該使用 UserTransaction.begin()、 UserTransaction.commit() 和 UserTransaction.rollback() .

    3、容器事務

    容器事務主要是J2EE應用伺服器提供的,容器事務大多是基于JTA完成,這是一個基于JNDI的,相當複雜的API實作。相對編碼實作JTA事務管理, 我們可以通過EJB容器提供的容器事務管理機制(CMT)完成同一個功能,這項功能由J2EE應用伺服器提供。這使得我們可以簡單的指定将哪個方法加入事 務,一旦指定,容器将負責事務管理任務。這是我們土建的解決方式,因為通過這種方式我們可以将事務代碼排除在邏輯編碼之外,同時将所有困難交給J2EE容 器去解決。使用EJB CMT的另外一個好處就是程式員無需關心JTA API的編碼,不過,理論上我們必須使用EJB.

     四、三種Java事務差異

    1、JDBC事務控制的局限性在一個資料庫連接配接内,但是其使用簡單。

    2、JTA事務的功能強大,事務可以跨越多個資料庫或多個DAO,使用也比較複雜。

    3、容器事務,主要指的是J2EE應用伺服器提供的事務管理,局限于EJB應用使用。

自動送出事務:每條單獨的語句都是一個事務。每個語句後都隐含一個commit。 (預設)

顯式事務:以begin transaction顯示開始,以commit或rollback結束。

隐式事務:當連接配接以隐式事務模式進行操作時,sql server資料庫引擎執行個體将在送出或復原目前事務後自動啟動新事務。無須描述事物的開始,隻需送出或復原每個事務。但每個事務仍以commit或rollback顯式結束。連接配接将隐性事務模式設定為打開之後,當資料庫引擎執行個體首次執行下列任何語句時,都會自動啟動一個隐式事務:alter table,insert,create,open ,delete,revoke ,drop,select, fetch ,truncate table,grant,update在發出commit或rollback語句之前,該事務将一直保持有效。在第一個事務被送出或復原之後,下次當連接配接執行以上任何語句時,資料庫引擎執行個體都将自動啟動一個新事務。該執行個體将不斷地生成隐性事務鍊,直到隐性事務模式關閉為止。

   五、事務并發處理可能引起的問題

髒讀(dirty read) 一個事務讀取了另一個事務尚未送出的資料,

不可重複讀(non-repeatable read) 一個事務的操作導緻另一個事務前後兩次讀取到不同的資料

幻讀(phantom read) 一個事務的操作導緻另一個事務前後兩次查詢的結果資料量不同。

舉例:

事務A、B并發執行時,

當A事務update後,B事務select讀取到A尚未送出的資料,此時A事務rollback,則B讀到的資料是無效的"髒"資料。

當B事務select讀取資料後,A事務update操作更改B事務select到的資料,此時B事務再次讀去該資料,發現前後兩次的資料不一樣。

當B事務select讀取資料後,A事務insert或delete了一條滿足A事務的select條件的記錄,此時B事務再次select,發現查詢到前次不存在的記錄("幻影"),或者前次的某個記錄不見了。

     六、儲存點(SavePoint)

JDBC定義了SavePoint接口,提供在一個更細粒度的事務控制機制。當設定了一個儲存點後,可以rollback到該儲存點處的狀态,而不是rollback整個事務。

Connection接口的setSavepoint和releaseSavepoint方法可以設定和釋放儲存點。

Spring 之注解事務 @Transactional

@Transactional

spring 事務注解

預設遇到throw new RuntimeException("...");會復原

需要捕獲的throw new Exception("...");不會復原

(預設spring事務隻在發生未被捕獲的 runtimeexcetpion時才復原。  

   spring aop  異常捕獲原理:被攔截的方法需顯式抛出異常,并不能經任何處理,這樣aop代理才能捕獲到方法的異常,才能進行復原,預設情況下aop隻捕獲 runtimeexception的異常,但可以通過  

配置來捕獲特定的異常并復原  

  換句話說在service的方法中不使用try catch 或者在catch中最後加上throw new runtimeexcetpion(),這樣程式異常時才能被aop捕獲進而復原,throw new XXX 其中XXX異常隻要是runtimeexception的子類都可以。

  解決方案: 

  方案1.例如service層處理事務,那麼service中的方法中不做異常捕獲,或者在catch語句中最後增加throw new RuntimeException()語句,以便讓aop捕獲異常再去復原,并且在service上層(webservice用戶端,view層action)要繼續捕獲這個異常并處理

  方案2.在service層方法的catch語句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();語句,手動復原,這樣上層就無需去處理異常(現在項目的做法))

class A{

@Transational

 public B(){

    this.C();  //不會復原

}

@Transational

public C(){

XXXXXXXXXXXXXX

}

}

原因:

aop 底層實作是:動态代理,動态代理分為cglib ,jdk二種。 
代理和目标即:proxy, target 的差別 方法中調用本類方法就相當于this。調用的是目标對象,沒有被增強。
并不是調用的代理類,是以不會被事物增強。
這個是容易犯的錯誤。
           

如果就調用内部方法可以使用cglib代理:AopContext currentProxy來進行cglib代理。不要實作接口,不用jdk動态代理。

// 指定復原

@Transactional(rollbackFor=Exception.class) 

    public void methodName() {

       // 不會復原

       throw new Exception("...");

    } 

//指定不復原

@Transactional(noRollbackFor=Exception.class)

    public ItimDaoImpl getItemDaoImpl() {

        // 會復原

        throw new RuntimeException("注釋");

    } 

    // 如果有事務,那麼加入事務,沒有的話建立一個(不寫的情況下)會導緻一個失敗,所有加入事務中的service都復原。适用于多個操作一個失敗全部復原。

    @Transactional(propagation=Propagation.REQUIRED) 

    // 容器不為這個方法開啟事務

    @Transactional(propagation=Propagation.NOT_SUPPORTED)

    // 不管是否存在事務,都建立一個新的事務,原來的挂起,新的執行完畢,繼續執行老的事務

    @Transactional(propagation=Propagation.REQUIRES_NEW) 

    // 必須在一個已有的事務中執行,否則抛出異常

    @Transactional(propagation=Propagation.MANDATORY)

    // 必須在一個沒有的事務中執行,否則抛出異常(與Propagation.MANDATORY相反)

    @Transactional(propagation=Propagation.NEVER) 

    // 如果其他bean調用這個方法,在其他bean中聲明事務,那就用事務.如果其他bean沒有聲明事務,那就不用事務.

    @Transactional(propagation=Propagation.SUPPORTS) 

@Transactional(propagation=Propagation.NESTED) 

// readOnly=true隻讀,不能更新,删除 

@Transactional (propagation = Propagation.REQUIRED,readOnly=true) 

// 設定逾時時間

@Transactional (propagation = Propagation.REQUIRED,timeout=30)

// 設定資料庫隔離級别

@Transactional (propagation = Propagation.REQUIRED,isolation=Isolation.DEFAULT)

事務的xml配置說明

<!--事務相關控制-->  

 <!-- 開啟事務支援 -->

<!--<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>-->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>  

</bean>    

<!--把事務控制在Service層,配置事務切入點,以及把事務切入點和事務屬性關聯起來-->    

<aop:config expose-proxy="true">       

<aop:pointcut id="txPointcut" expression="execution(* org.spring.service..*.*(..))" />    

<aop:advisor id="txAdvisor" advice-ref="txAdvice" pointcut-ref="txPointcut"  />    

</aop:config>

事務控制通過2中方式

1、這裡需要注意,這種事務配置是自動識别方法來完成事務控制

<!-- 事務增強 -->

<tx:advice id="txAdvice" transaction-manager="transactionManager">    

<tx:attributes>  

<tx:method name="getAcceptValue" propagation="REQUIRES_NEW"/>  

<tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>

<tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>       

<tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>

<tx:method name="create*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>           

<tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>     

<tx:method name="modify*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>    

<tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>   

<tx:method name="find*"  propagation="SUPPORTS" read-only="false" rollback-for="Exception"/>   

<tx:method name="select*" propagation="SUPPORTS" read-only="false" rollback-for="Exception"/> 

<tx:method name="qry*" propagation="SUPPORTS" read-only="false" rollback-for="Exception"/> 

<tx:method name="query*" propagation="SUPPORTS" read-only="false" rollback-for="Exception"/> 

<tx:method name="*"/>

</tx:attributes>    

</tx:advice>

事務增強以後,service層出現以配置檔案中類似開頭(insert\add\save\...)的方法都會自動增加事務,出現異常會自動復原。

在實際寫代碼的時候,如果異常被catch住而且沒有向上抛出的話,事務就無法復原。因為程式不知道是否發省了異常。如果控制事務,盡量出現異常要抛出。

Spring事務管理是根據異常來進行復原操作; Spring與Mybatis整合時,雖然在Service方法中并沒有check異常,但是如果資料庫有異常發生,預設會進行事務復原。 Spring 如果不添加rollbackFor等屬性,Spring碰到Unchecked Exceptions都會復原,不僅是RuntimeException,也包括Error。 如果在事務方法中捕獲異常并進行處理,一定要繼續抛出異常并在Spring事務管理中進行rollbak-for配置。

2、利用@Transaction注解方式進行事務控制

<!-- 支援 @Transactional 标記 -->

<tx:annotation-driven />

事務管理方式

spring支援程式設計式事務管理和聲明式事務管理兩種方式。

程式設計式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對于程式設計式事務管理,spring推薦使用TransactionTemplate。

聲明式事務管理建立在AOP之上的。其本質是對方法前後進行攔截,然後在目标方法開始之前建立或者加入一個事務,在執行完目标方法之後根據執行情況送出或者復原事務。聲明式事務最大的優點就是不需要通過程式設計的方式管理事務,這樣就不需要在業務邏輯代碼中摻雜事務管理的代碼,隻需在配置檔案中做相關的事務規則聲明(或通過基于@Transactional注解的方式),便可以将事務規則應用到業務邏輯中。

顯然聲明式事務管理要優于程式設計式事務管理,這正是spring倡導的非侵入式的開發方式。聲明式事務管理使業務代碼不受污染,一個普通的POJO對象,隻要加上注解就可以獲得完全的事務支援。和程式設計式事務相比,聲明式事務唯一不足地方是,後者的最細粒度隻能作用到方法級别,無法做到像程式設計式事務那樣可以作用到代碼塊級别。但是即便有這樣的需求,也存在很多變通的方法,比如,可以将需要進行事務管理的代碼塊獨立為方法等等。

聲明式事務管理也有兩種常用的方式,一種是基于tx和aop名字空間的xml配置檔案,另一種就是基于@Transactional注解。顯然基于注解的方式更簡單易用,更清爽。

自動送出(AutoCommit)與連接配接關閉時的是否自動送出

自動送出

預設情況下,資料庫處于自動送出模式。每一條語句處于一個單獨的事務中,在這條語句執行完畢時,如果執行成功則隐式的送出事務,如果

執行失敗則隐式的復原事務。

對于正常的事務管理,是一組相關的操作處于一個事務之中,是以必須關閉資料庫的自動送出模式。不過,這個我們不用擔心,spring會将底層連接配接的自動送出特性設定為false。

org/springframework/jdbc/datasource/DataSourceTransactionManager.java

學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明
1 // switch to manual commit if necessary. this is very expensive in some jdbc drivers,
 2 // so we don't want to do it unnecessarily (for example if we've explicitly
 3 // configured the connection pool to set it already).
 4 if (con.getautocommit()) {
 5     txobject.setmustrestoreautocommit(true);
 6     if (logger.isdebugenabled()) {
 7         logger.debug("switching jdbc connection [" + con + "] to manual commit");
 8     }
 9     con.setautocommit(false);
10 }
           
學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明

有些資料連接配接池提供了關閉事務自動送出的設定,最好在設定連接配接池時就将其關閉。但C3P0沒有提供這一特性,隻能依靠spring來設定。

因為JDBC規範規定,當連接配接對象建立時應該處于自動送出模式,這是跨DBMS的預設值,如果需要,必須顯式的關閉自動送出。C3P0遵守這一規範,讓客戶代碼來顯式的設定需要的送出模式。

連接配接關閉時的是否自動送出

當一個連接配接關閉時,如果有未送出的事務應該如何處理?JDBC規範沒有提及,C3P0預設的政策是復原任何未送出的事務。這是一個正确的政策,但JDBC驅動提供商之間對此問題并沒有達成一緻。

C3P0的autoCommitOnClose屬性預設是false,沒有十分必要不要動它。或者可以顯式的設定此屬性為false,這樣會更明确。

基于注解的聲明式事務管理配置

spring-servlet.xml

學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明
1 <!-- transaction support-->
2 <!-- PlatformTransactionMnager -->
3 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
4     <property name="dataSource" ref="dataSource" />
5 </bean>
6 <!-- enable transaction annotation support -->
7 <tx:annotation-driven transaction-manager="txManager" />
           
學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明

還要在spring-servlet.xml中添加tx名字空間

學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明
1 ...
 2     xmlns:tx="http://www.springframework.org/schema/tx"
 3     xmlns:aop="http://www.springframework.org/schema/aop"
 4     xsi:schemaLocation="
 5     ...
 6  
 7 http://www.springframework.org/schema/tx
 8  
 9  
10 http://www.springframework.org/schema/tx/spring-tx.xsd
11  
12     ...
           
學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明

MyBatis自動參與到spring事務管理中,無需額外配置,隻要org.mybatis.spring.SqlSessionFactoryBean引用的資料源與DataSourceTransactionManager引用的資料源一緻即可,否則事務管理會不起作用。

另外需要下載下傳依賴包aopalliance.jar放置到WEB-INF/lib目錄下。否則spring初始化時會報異常

java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor

spring事務特性

spring所有的事務管理政策類都繼承自org.springframework.transaction.PlatformTransactionManager接口

學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明
1 public interface PlatformTransactionManager {
2  
3   TransactionStatus getTransaction(TransactionDefinition definition)
4     throws TransactionException;
5  
6   void commit(TransactionStatus status) throws TransactionException;
7  
8   void rollback(TransactionStatus status) throws TransactionException;
9 }
           
學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明

其中TransactionDefinition接口定義以下特性:

事務隔離級别

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

  • TransactionDefinition.ISOLATION_DEFAULT:這是預設值,表示使用底層資料庫的預設隔離級别。對大部分資料庫而言,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級别表示一個事務可以讀取另一個事務修改但還沒有送出的資料。該級别不能防止髒讀,不可重複讀和幻讀,是以很少使用該隔離級别。比如PostgreSQL實際上并沒有此級别。
  • 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。

事務逾時

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

預設設定為底層事務系統的逾時值,如果底層資料庫事務系統沒有設定逾時值,那麼就是none,沒有逾時限制。

事務隻讀屬性

隻讀事務用于客戶代碼隻讀但不修改資料的情形,隻讀事務用于特定情景下的優化,比如使用Hibernate的時候。

預設為讀寫事務。

spring事務復原規則

訓示spring事務管理器復原一個事務的推薦方法是在目前事務的上下文内抛出異常。spring事務管理器會捕捉任何未處理的異常,然後依據規則決定是否復原抛出異常的事務。

預設配置下,spring隻有在抛出的異常為運作時unchecked異常時才復原該事務,也就是抛出的異常為RuntimeException的子類(Errors也會導緻事務復原),而抛出checked異常則不會導緻事務復原。

可以明确的配置在抛出那些異常時復原事務,包括checked異常。也可以明确定義那些異常抛出時不復原事務。

還可以程式設計性的通過setRollbackOnly()方法來訓示一個事務必須復原,在調用完setRollbackOnly()後你所能執行的唯一操作就是復原。

@Transactional注解

@Transactional屬性

屬性 類型 描述
value String 可選的限定描述符,指定使用的事務管理器
propagation enum: Propagation 可選的事務傳播行為設定
isolation enum: Isolation 可選的事務隔離級别設定
readOnly boolean 讀寫或隻讀事務,預設讀寫
timeout int (in seconds granularity) 事務逾時時間設定
rollbackFor Class對象數組,必須繼承自Throwable 導緻事務復原的異常類數組
rollbackForClassName 類名數組,必須繼承自Throwable 導緻事務復原的異常類名字數組
noRollbackFor Class對象數組,必須繼承自Throwable 不會導緻事務復原的異常類數組
noRollbackForClassName 類名數組,必須繼承自Throwable 不會導緻事務復原的異常類名字數組

用法

@Transactional 可以作用于接口、接口方法、類以及類方法上。當作用于類上時,該類的所有 public 方法将都具有該類型的事務屬性,同時,我們也可以在方法級别使用該标注來覆寫類級别的定義。

雖然 @Transactional 注解可以作用于接口、接口方法、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該注解,因為這隻有在使用基于接口的代理時它才會生效。另外, @Transactional 注解應該隻被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者預設可見性的方法上使用 @Transactional 注解,這将被忽略,也不會抛出任何異常。

預設情況下,隻有來自外部的方法調用才會被AOP代理捕獲,也就是,類内部方法調用本類内部的其他方法并不會引起事務行為,即使被調用方法使用@Transactional注解進行修飾。

學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明
1 @Transactional(readOnly = true)
 2 public class DefaultFooService implements FooService {
 3  
 4   public Foo getFoo(String fooName) {
 5     // do something
 6   }
 7  
 8   // these settings have precedence for this method
 9   //方法上注解屬性會覆寫類注解上的相同屬性
10   @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
11   public void updateFoo(Foo foo) {
12     // do something
13   }
14 }
           
學習筆記-------spring 事務控制Spring 之注解事務 @Transactional @Transactional事務的xml配置說明

嵌套事務復原說明

對于嵌套事務。

1.外部起事務,内部起事務,内外都有Try Catch

内部出錯:如果内部事務出錯,内部和外部事物全部復原,外部復原之前的操作全部不存在,但是之後的操作繼續執行。

外部出錯:如果外部事物出錯,内部和外部事物全部復原,外部復原之前的操作全部不存在,但是之後的操作繼續執行。

注:如果内部的事務不起事務名稱,内部如果出錯,将會復原掉會話中的全部事務,而且報異常。

2.外部起事務,内部起事務,内部沒有Try Catch

内部出錯:如果内部事務出錯,内部和外部事物全部復原,外部復原之前的操作全部不存在,但是之後的操作繼續執行。

外部出錯:如果外部事務出錯,内部和外部事物全部復原,外部復原之前的操作全部不存在,但是之後的操作繼續執行。

------------------------------------------------------------------------------------------------------------

3.外部起事務,内部不起事務,但有Try Catch。

内部出錯:外部事物正常送出,外部事物不會進入ROLLBACK,内部出錯之後的記錄也會正常執行。内部操作中,Try部分在錯誤出現之前的操作正常,Try部分在操作之後的操作不執行,然後進入Catch塊中執行操作。

外部出錯:内部和外部事物全部復原,外部復原之前的操作全部不存在,但是之後的操作繼續執行。

4.外部起事務,内部不起事務,但沒有Try Catch.

内部出錯:如果内部事務出錯,内部和外部事物全部復原,外部復原之前的操作全部不存在,但是之後的操作繼續執行。

外部出錯:如果外部事務出錯,内部和外部事物全部復原,外部復原之前的操作全部不存在,但是之後的操作繼續執行。

------------------------------------------------------------------------------------------------------------

5.外部不起事務,内部起事務,但有Try Catch.

内部出錯:外部操作被正常執行,内部ROLLBACK操作前全部復原,之後的操作正常執行。

外部出錯:出錯操作之前的操作不會復原,出錯之後的操作不執行,跳入Catch塊中,内部事務不會復原。

6.外部不起事務,内部起事務,但沒有Try Catch.

内部出錯:外部操作被正常執行,内部ROLLBACK操作前全部復原。由于沒有catch塊,是以外部操作全部執行。

外部出錯:内部事務正常送出,外部隻有當條記錄失敗,其他操作正常執行,但是有嚴重錯誤報出來。

-------------------------------------------------------

對于事務儲存點

事務儲存點隻有SAVE和ROLLBACK操作,當外部調用内部儲存點,内部出現問題不影響外部事務,外部操作正常執行。當外部操作出現問題時,内部所有操作都復原掉。

如:外部起事務,内部起儲存點,内外都有Try Catch

内部出錯:外部操作正常,不進入Catch,内部事務復原到儲存點,之後的繼續執行。

外部出錯:如果外部事物在儲存點之前出現異常,那麼外部和内部所有操作復原。如果外部事物在儲存點之前出現異常,由于儲存點已經送出了事務,導緻外部rollback找不到對應的事務點。

繼續閱讀