事務(@Transactional注解)的用法和實例


參數

@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的子類,這是有關數據庫的異常會回滾的原因。


免責聲明!

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



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