Spring宣告式事務@Transactional使用

王富貴兒。發表於2020-11-10

背景

作為一個後端開發,@Transactional一直在用,但總會碰到各種離奇的不生效的情況,每次都是到處查資料解決。就想寫一篇文章整理一下,後面遇到就不用到處找了,有新情況也再補充。

@Transactional

宣告式事務

spring支援 程式設計式事務宣告式事務 兩種。程式設計式事務也就是用程式碼手動控制事務的開始、提交或回滾,這樣業務程式碼就變得不純粹,功能程式碼和輔助程式碼雜糅到一起,並且會有許多重複程式碼。所以我們一般使用宣告式事務。宣告式事務一般有兩種方式,一是基於tx和aop名稱空間的xml配置檔案,二是使用@Transactional註解。目前使用比較廣泛的就是@Transactional註解。

屬性

屬性型別描述
value、transactionManagerString可選的限定描述符,指定使用的事務管理器
propagationenum: Propagation可選的事務傳播行為設定
isolationenum: Isolation可選的事務隔離級別設定
readOnlyboolean“讀寫”或“只讀”事務,預設false讀寫
timeoutint (in seconds granularity)事務超時時間設定,預設-1
rollbackForClass物件陣列,必須繼承自Throwable導致事務回滾的異常類陣列
rollbackForClassName類名陣列,必須繼承自Throwable導致事務回滾的異常類名字陣列
noRollbackForClass物件陣列,必須繼承自Throwable不會導致事務回滾的異常類陣列
noRollbackForClassName類名陣列,必須繼承自Throwable不會導致事務回滾的異常類名字陣列

value、transactionManager

指定事務管理器的名稱,一般用在多資料來源應用的事務處理中,用來明確指定使用哪個資料來源的事務管理

propagation:事務傳播行為【todo 後面寫demo程式碼跑一下驗證

  • Propagation.REQUIRED
    • 如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。這是預設值。
    • 【外層事務和內層事務是一個事務,要提交一起提交,要回滾一起回滾】
  • Propagation.SUPPORTS
    • 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。
    • 【如果有外層事務,那麼和Propagation.REQUIRED相同。如果沒有外層事務,以非事務的方式執行】
  • Propagation.MANDATORY
    • 如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常
    • 【如果有外層事務,那麼和Propagation.REQUIRED相同。如果沒有外層事務,丟擲異常】
  • Propagation.REQUIRES_NEW
    • 建立一個新的事務,如果當前存在事務,則把當前事務掛起。
    • 【外層事務回滾,內部事務正常提交;內部事務回滾,外部事務若對異常進行了捕獲,沒有再向上拋,則外部事務繼續執行】
  • Propagation.NOT_SUPPORTED
    • 以非事務方式執行,如果當前存在事務,則把當前事務掛起。
    • 【外層事務不影響,內層以非事務方式執行】
  • Propagation.NEVER
    • 以非事務方式執行,如果當前存在事務,則丟擲異常。
  • Propagation.NESTED
    • 如果當前存在事務,則建立一個事務作為當前事務的巢狀事務來執行;如果當前沒有事務,則該取值等價於Propagation.REQUIRED。
    • 【外部事務回滾,內部事務一定會回滾;內部事務回滾,外部事務繼續執行】

Propagation.REQUIRES_NEW、Propagation.NESTED、Propagation.REQUIRED 對比

定義serviceA.methodA()以Propagation.REQUIRED修飾;
定義serviceB.methodB()以表格中三種方式修飾;
methodA中呼叫methodB

異常狀態Propagation.REQUIRES_NEW
(兩個獨立事務)
Propagation.NESTED
(B的事務巢狀在A的事務中)
Propagation.REQUIRED
(同一個事務)
methodA拋異常
methodB正常
A回滾,B正常提交A與B一起回滾A與B一起回滾
methodA正常
methodB拋異常
1.如果A中捕獲B的異常,並沒有繼續向上拋異常,則B先回滾,A再正常提交;
2.如果A未捕獲B的異常,預設則會將B的異常向上拋,則B先回滾,A再回滾
B先回滾,A再正常提交A與B一起回滾
methodA拋異常
methodB拋異常
B先回滾,A再回滾A與B一起回滾A與B一起回滾
methodA正常
methodB正常
B先提交,A再提交A與B一起提交A與B一起提交

isolation:事務隔離級別

和資料庫的事務隔離級別含義是相同的,只是多了default。區別是isolation指定的是當前連線會話的事務隔離級別,而資料庫指的是當前資料庫全域性的事務隔離級別。當二者不相同時,以當前會話的隔離級別為準。

  • Isolation.DEFAULT
    • 使用資料庫預設的事務隔離級別
  • Isolation.READ_UNCOMMITTED
    • 讀未提交
  • Isolation.READ_COMMITTED
    • 讀已提交
  • Isolation.REPEATABLE_READ
    • 可重複讀
  • Isolation.SERIALIZABLE
    • 序列化

readOnly

  • 設定當前事務是否為只讀事務,設定為true表示只讀,false則表示可讀寫,預設值為false
  • 如果設定為true卻執行了寫的操作會發生什麼呢?後面寫demo跑一下

timeout

  • 設定事務的超時秒數,預設值為-1表示永不超時。超時事務將會回滾。

rollbackFor

  • 該屬性用於設定需要進行回滾的異常類陣列,當方法中丟擲指定異常陣列中的異常時,則進行事務回滾。例如:
  • 指定單一異常類:@Transactional(rollbackFor=RuntimeException.class)
  • 指定多個異常類:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

  • 該屬性用於設定需要進行回滾的異常類名稱陣列,當方法中丟擲指定異常名稱陣列中的異常時,則進行事務回滾。
  • 指定單一異常類名稱:@Transactional(rollbackForClassName="RuntimeException")
  • 指定多個異常類名稱:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

  • 該屬性用於設定不需要進行回滾的異常類陣列,當方法中丟擲指定異常陣列中的異常時,不進行事務回滾。

  • 指定單一異常類:@Transactional(noRollbackFor=RuntimeException.class)

  • 指定多個異常類:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

  • 該屬性用於設定不需要進行回滾的異常類名稱陣列,當方法中丟擲指定異常名稱陣列中的異常時,不進行事務回滾。
  • 指定單一異常類名稱:@Transactional(noRollbackForClassName="RuntimeException")
  • 指定多個異常類名稱:@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

使用

  • @Transactional要修飾在介面實現類或介面實現方法上,而不是介面類中
  • 方法上註解屬性會覆蓋類註解上的相同屬性
  • 父類的宣告的@Transactional會對子類的所有方法進行事務增強;子類覆蓋重寫父類方式可覆蓋其@Transactional中的宣告配置
  • 只有來自外部的方法呼叫才會被AOP代理捕獲,也就是,類內部方法呼叫本類內部的其他方法並不會引起事務行為,即使被呼叫方法使用@Transactional註解進行修飾
  • @Transactional修飾 public 的方法才起作用
  • 介面中異常(執行時異常)被捕獲而沒有被丟擲,將不會進行事務回滾
     

原理

【todo 我不配,用好了再學習一下】

參考

透徹的掌握 Spring 中 @transactional 的使用

@Transactional

Spring中的@Transactional(rollbackFor = Exception.class)屬性詳解

關於PROPAGATION_NESTED的理解

Spring事務隔離級別與MySQL設定的級別不一樣怎麼辦

Spring事務隔離級別與Mysql InnoDB事務隔離級別的關係

Spring 使用註解方式進行事務管理

相關文章