參數
@Transactional可以配制那些參數及以其所代表的意義:
參數 | 意義 |
---|---|
isolation | 事務隔離級別 |
propagation | 事務傳播機制 |
readOnly | 事務讀寫性 |
noRollbackFor | 一組異常類,遇到時不回滾。默認為{}。 |
noRollbackForClassName | 一組異常類名,遇到時不回滾,默認為{} |
rollbackFor | 一組異常類,遇到時回滾 |
rollbackForClassName | 一組異常類名,遇到時回滾 |
timeout | 超時時間,以秒為單位 |
value | 可選的限定描述符,指定使用的事務管理器 |
isolation
isolation
屬性可配置的值有:
- Isolation.READ_COMMITTED :使用各個數據庫默認的隔離級別
- Isolation.READ_UNCOMMITTED :讀未提交數據(會出現臟讀,不可重復讀,幻讀)
- Isolation.READ_COMMITTED :讀已提交的數據(會出現不可重復讀,幻讀)
- Isolation.REPEATABLE_READ :可重復讀(會出現幻讀)
- Isolation.SERIALIZABLE :串行化
數據庫默認隔離級別
- MYSQL: 默認為REPEATABLE_READ級別
- SQLSERVER: 默認為READ_COMMITTED
- Oracle 默認隔離級別 READ_COMMITTED
propagation
propagation
屬性可配置的值有:
傳播機制 | 說明 |
---|---|
Propagation.REQUIRED | 如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。這是 最常見的選擇,也是Spring的默認傳播機制。 |
Propagation.SUPPORTS | 支持當前事務,如果當前沒有事務,就以非事務方式執行。 |
Propagation.MANDATORY | 使用當前的事務,如果當前沒有事務,就拋出異常。 |
Propagation.REQUIRES_NEW | 新建事務,如果當前存在事務,把當前事務掛起。 |
Propagation.NOT_SUPPORTED | 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 |
Propagation.NEVER | 以非事務方式執行,如果當前存在事務,則拋出異常。 |
Propagation.NESTED | 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與 PROPAGATION_REQUIRED 類似的操作。 |
上一篇寫事務的文章中已經把這兩個屬性說得很清楚了,這里就不再贅述了。
readOnly
默認情況下是false,可以顯示指定為true, 告訴程序該方法下使用的是只讀操作,如果進行其他非讀操作,則會跑出異常;
-
概念: 從這一點設置的時間點開始(時間點a)到這個事務結束的過程中,其他事務所提交的數據,該事務將看不見!(查詢中不會出現別人在時間點a之后提交的數據)
-
應用場合: 如果你一次執行單條查詢語句,則沒有必要啟用事務支持,數據庫默認支持SQL執行期間的讀一致性; 如果你一次執行多條查詢語句,例如統計查詢,報表查詢,在這種場景下,多條查詢SQL必須保證整體的讀一致性,否則,在前條SQL查詢之后,后條SQL查詢之前,數據被其他用戶改變,則該次整體的統計查詢將會出現讀數據不一致的狀態,此時,應該啟用事務支持。
【注意是一次執行多次查詢來統計某些信息,這時為了保證數據整體的一致性,要用只讀事務】
rollbackForClassName/rollbackFor
Spring默認情況下會對運行期例外(RunTimeException)進行事務回滾。這個例外是unchecked,如果遇到checked意外就不回滾。
用來指明回滾的條件是哪些異常類或者異常類名。
noRollbackForClassName/noRollbackFor
用來指明不回滾的條件是哪些異常類或者異常類名。
timeout
用於設置事務處理的時間長度,阻止可能出現的長時間的阻塞系統或者占用系統資源。單位為秒。如果超時設置事務回滾,並拋出TransactionTimedOutException異常。
value
value這里主要用來指定不同的事務管理器;主要用來滿足在同一個系統中,存在不同的事務管理器。
比如在Spring中,聲明了兩種事務管理器txManager1, txManager2.然后,用戶可以根據這個參數來根據需要指定特定的txManager.
- 存在多個事務管理器的情況: 在一個系統中,需要訪問多個數據源,則必然會配置多個事務管理器。
注意點
- 不要在接口上使用注解,可能會無效,要在實現類的具體方法上寫。
- 可以在類級別上使用注釋,但是會使類下的所有方法都有事務,影響效率。
- 只能對public方法使用事務,@Transactional注解的方法都是被外部其他類調用才有效,故只能是public。
- 使用了@Transactional的方法,對同一個類里面的方法調用, @Transactional無效。比如有一個類Test,它的一個方法A,A再調用Test本類的方法B(不管B是否public還是private),但A沒有聲明注解事務,而B有。則外部調用A之后,B的事務是不會起作用的。
不回滾的情況
spring事務機制:
- 默認spring事務只在發生未被捕獲的RuntimeException時才回滾。
-
spring aop異常捕獲原理:被攔截的方法需要顯式拋出異常,不能經過處理,這樣aop代理才能捕獲到方法的異常,才能進行回滾。
默認情況下aop只捕獲RuntimeException的異常,但可以通過配置來捕獲特定的異常並回滾。換句話說,在service的方法中不使用try-catch或者在catch中最后加上throw new RuntimeException(),這樣程序發生異常時才能被aop捕獲進而回滾。
-
解決方案:
-
例如Service層處理事務,那么Service中的方法中不做異常捕獲,或者在catch語句中最后增加throw new RuntimeException()語句,以便aop捕獲異常再去回滾,並且在service上層要繼續捕獲這個異常並處理。
-
在service層方法的catch語句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();語句,手動回滾,這樣上層就無需去處理異常。
-
SQLException本身是受檢查的異常,但是在Spring框架下,拋出的是org.springframework.dao包中的異常,都是RuntimeException的子類,這是有關數據庫的異常會回滾的原因。
-