@Transaction中的屬性信息
value :
當在配置文件中配有多個事務管理器時,可用該屬性指定選擇哪一個事務管理器。java
propagation :
事務的傳播行爲。所謂事務的傳播行爲,是指在當前事務開啓以前,已經有一個事務上下文存在了的狀況(好比說咱們給方法A和方法B分別加上了事務,而後在A中調用了B,這時就須要選擇事務傳播行爲,使A作出期待的應對。數據庫
該屬性包含的可選項以下 :併發
- REQUIRED(默認):
- 若方法A調用時,上下文中存在事務,則加入當前事務
- 若方法A調用時,上下文中沒有事務,則新建一個事務
- 當在方法A調用方法B時,方法A、B將使用同一個事務
- 若是方法B發生異常須要回滾時,將回滾整個事務
- REQUIRED_NEW :
- 對於方法A與B,不管方法調用時是否存在事務,都會開啓一個新的事務
- 且若是方法調用時存在事務,當前事務將被延緩
- 若是方法B發生異常,將不會致使方法A的回滾
- NESTED :
- 與REQUIRED_NEW相似,但支持JDBC,不支持JPA或Hibernate
- SUPPORTS :
- 若是方法調用時,上下文中已經開啓了事務,就使用這個事務
- 若是方法調用時,上下文中沒有事務,就不使用事務
- NOT_SUPPORTS :
- 以非事務的方式運行,若是存在事務,在方法調用到結束階段事務都將被掛起
- NEVER :
- MANDATORY :
- 強制方法在事務中執行,若是存在事務,則加入當前事務
- 若是不存在事務,則將拋出異常
isolation :
事務的隔離級別。所謂事務的隔離級別,是指若干個併發的事務之間的隔離程度,由低到高依次分別爲 :read uncommited(讀未提交)、read commited(讀提交)、read repeatable(讀重複)、serializable(序列化)
;這四個級別能夠逐個解決髒讀、不可重複讀、幻讀
這幾類問題。spa
該屬性包含的可選項以下 :代理
- READ_UNCOMMITED :
- 最低級別的事務隔離級別,它容許另外一個事務能夠看到這個事務未提交的數據;可致使髒讀,不可重複讀,以及幻讀
- READ_COMMITED :
- 保證一個事務提交以後才能被另外一個事務讀取;可防止髒讀,但可能致使不可重複讀和幻讀
- REPEATABLE_READ :
- 不只能實現 READ_COMMITED 的功能,還能進行以下限制 :當A事務讀取了一條數據時,B事務將不容許修改這條記錄;阻止髒讀和不可重複讀,但可能致使幻讀
- SERIALIZABLE :
- 開銷最大但最可靠的事務隔離級別,事務被處理爲順序執行;除了防止髒讀、不可重複讀以外,還避免了幻讀
- DEFUALT :
- 使用當前數據庫的默認隔離級別,如 Oracle、SqlServer 是 READ_COMMITED,MySQL 是 REPEATABLE_READF
其中,髒讀、不可重複讀、幻讀概念以下 :code
- 髒讀 :讀取了未提交的數據
- 好比說A操做試圖將帳戶餘額修由2000修改成1000,B操做讀取了該修改後,試圖在原餘額的基礎上增長1000;在B操做執行期間,A操做發生錯誤致使回滾,帳戶餘額又變回了2000;那麼,當B提交操做後,帳戶餘額本該有2000+1000=3000,但因爲B讀取了錯誤的數據,即髒數據,此時的帳戶餘額就僅剩下1000+1000=2000了。
- 不可重複讀 :先後屢次讀取,數據內容不一致
- 好比說,咱們有一個操做A須要屢次讀取帳戶餘額,在A的第一次讀取中,餘額爲1000,這時另外一個操做B將餘額修改成了2000,那麼在A的第二次讀取中,就會發現餘額變爲了2000,和第一次讀取的數據不同了;系統在同一個操做中沒法讀取同一個數據,稱爲不可重複讀。
- 幻讀 :先後屢次讀取,數據總量不一致
- 好比說事務A在執行讀取操做時,須要屢次統計數據的總量,前一次查詢數據總量後,此時B事務執行了新增數據的操做並提交,這時候A再去讀取,就會像產生幻覺同樣平白多讀出了幾條數據,所以稱爲幻讀。
timeout :
事務的過時時間。默認爲當前數據庫的事務過時時間orm
readonly :
指定當前事務是否爲只讀事務,默認爲false對象
rollbackFor :
指定哪一個或哪些異常發生時,須要引發事務回滾,默認爲Throwable的子類事務
noRollBackFor :
指定哪一個或哪些異常發生時,不引發事務回滾it
Spring中註解方式的事務實現機制
在應用系統調用聲明 @Transactional 的目標方法時,Spring Framework :
- 默認使用 AOP 代理
- 在代碼運行時生成一個代理對象
根據 @Transaction 的屬性配置信息,這個代理對象將 :
- 決定該目標方法是否由攔截器 TransactionInterceptor 來攔截
TransactionInterceptor在攔截時,會 :
- 首先在目標方法開始執行以前建立並加入事務
- 而後執行目標方法
- 最後根據執行狀況是否出現異常,利用抽象事務管理器 AbstarctPlatformTransactionManager 操做數據源 DataSource 提交或回滾事務。
其餘注意事項
@Transaction只有應用到public方法纔能有效
這是由於在使用 Spring AOP 代理時,Spring在調用 TransactionInterceptor 攔截器對方法進行攔截以前,CglibAopProxy 的一個內部類中的 intercept 方法會間接調用 AbstractFallbackTransactionAttributeSource(Spring 經過這個類獲取 @Transaction 註解的事務屬性配置屬性信息)的 computeTransactionAttribute 方法。
這個方法會檢查目標方法的修飾符是否是 public,若是不是,就不會獲取 @Transaction 的屬性配置信息,最終形成不會使用 TransactionInterceptor 來攔截改目標方法,從而致使事務管理不被進行。
避免 Spring 中的 AOP 自調用問題
在 Spring 的 AOP 代理下,只有當目標方法由外部調用的時候,該目標方法才能由 Spring 生成的代理對象來管理。若同一類中,其餘某個沒有 @Transaction 註解的方法調用了有 @Transaction 註解的方法,這個有 @Transaction 註解的方法的事務將被忽略,不會發生回滾。
好比以下這種狀況,咱們有一個Demo類,類中有兩個方法 A 和 B,A 上聲明瞭事務,而 B 上沒有時,當 B 調用了 A,A 中的事務將不會生效。
@Server
public class Demo {
public void methodB() {
methodA();
}
@Transaction
public void methodA() {
}
}
複製代碼
這是由於,當咱們使用 AOP 進行攔截時,首先會建立一個 Demo 的代理類,這個時候咱們的系統中就會存在兩個 Demo 對象了 :一個是目標 Demo 對象
,一個是這個生成的代理 Demo 對象
。若是在代理類的 A 方法中調用代理類的 B 方法,這時候 AOP 攔截是能夠生效的,可是,若是在代理類的 A 方法中調用目標類的 B 方法,這時候 AOP 攔截就不會生效了。