詳解Spring中REQUIRED事務的回滾機制詳解
在 Spring 的事務管理中,REQUIRED 是最常用也是默認的事務傳播屬性。很多開發(fā)者在使用時會遇到一個常見的困惑:為什么內(nèi)部方法拋出的異常即便被外層捕獲了,事務還是會整體回滾? 本文將深入剖析 REQUIRED 下的事務回滾機制及其背后的原理。
1. REQUIRED 的定義
- 默認傳播屬性。
- 如果當前存在事務:加入當前事務。
- 如果沒有事務:創(chuàng)建一個新事務。
這意味著調(diào)用鏈上的所有方法都運行在同一個物理事務里,彼此之間沒有隔離。只要其中一個方法觸發(fā)回滾條件,整個事務都會被撤銷。
2. REQUIRED 下的回滾機制
2.1 異常觸發(fā)回滾
Spring 默認回滾規(guī)則:
- 運行時異常(
RuntimeException)和錯誤(Error):觸發(fā)回滾。 - 受檢異常(
CheckedException):不會觸發(fā)回滾,除非在@Transactional(rollbackFor = Exception.class)中顯式指定。
2.2 回滾狀態(tài)傳播
假設調(diào)用鏈如下:
@Transactional(propagation = Propagation.REQUIRED)
public void outer() {
try {
inner();
} catch (Exception e) {
// 異常被捕獲
}
}
@Transactional(propagation = Propagation.REQUIRED)
public void inner() {
throw new RuntimeException("內(nèi)部錯誤");
}
執(zhí)行過程:
outer()啟動時創(chuàng)建事務。inner()加入同一事務并拋出異常。- Spring 的事務攔截器捕獲異常 → 標記當前事務為 rollback-only。
- 即便外層
outer()捕獲了異常,rollback-only 標記不會自動清除。 - 最終事務提交時,Spring 檢查到 rollback-only → 調(diào)用
rollback()而不是commit()。
因此,捕獲異常并不能阻止事務回滾。
3. 為什么捕獲異常也會回滾?
原因在于 Spring 的事務是基于 事務狀態(tài)標記 而不是你的 try-catch 來決定的:
- 方法拋出異常 →
TransactionInterceptor判斷是否需要回滾。 - 如果符合規(guī)則 →
status.setRollbackOnly()。 - 外層即便捕獲異常,也只是業(yè)務層邏輯“消化”了異常,但事務狀態(tài)已經(jīng)不可提交。
最終由事務管理器在 commit() 階段檢查 rollback-only 標記,決定整體回滾。
4. 如何避免“誤回滾”?
如果確實需要內(nèi)部異常不影響外部事務,可以考慮以下方式:
4.1 修改回滾規(guī)則
@Transactional(noRollbackFor = RuntimeException.class)
public void inner() {
throw new RuntimeException("不會觸發(fā)回滾");
}
但這種方式風險極高,可能提交錯誤數(shù)據(jù)。
4.2 手動清理事務狀態(tài)(不推薦)
catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(false);
}
此方式非常危險,通常不建議。
4.3 使用其他傳播屬性(推薦)
- REQUIRES_NEW:為內(nèi)部方法開啟新事務,失敗只影響內(nèi)部,不影響外部。
- NESTED:使用保存點,內(nèi)部失敗可回滾到保存點,外部事務繼續(xù)。
這兩種方式才是更優(yōu)雅的解決方案。
5. Spring 內(nèi)部執(zhí)行流程
核心邏輯在 TransactionAspectSupport.invokeWithinTransaction():
- 獲取或創(chuàng)建事務。
- 執(zhí)行目標方法。
- 捕獲異常 → 判斷是否需要回滾 → 設置 rollback-only。
- 方法結(jié)束 → 根據(jù)狀態(tài)決定
commit()還是rollback()。
6. 總結(jié)
REQUIRED下,所有方法共享一個事務。- 任意方法異常觸發(fā) rollback-only → 整體回滾。
- 捕獲異常≠事務安全,Spring 根據(jù)事務狀態(tài)決定提交還是回滾。
- 如果需要更細粒度的控制,應使用
REQUIRES_NEW或NESTED。
一句話總結(jié):在 Spring 的 REQUIRED 模式下,事務是一榮俱榮、一損俱損的整體,內(nèi)部異常即便被捕獲也會讓整個事務回滾,真正想做到“局部回滾”需要換傳播屬性來實現(xiàn)。
到此這篇關(guān)于詳解Spring中REQUIRED事務的回滾機制詳解的文章就介紹到這了,更多相關(guān)Spring REQUIRED 事務回滾內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
idea數(shù)據(jù)庫驅(qū)動下載失敗的問題及解決
這篇文章主要介紹了idea數(shù)據(jù)庫驅(qū)動下載失敗的問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
SpringBoot整合Druid并開啟監(jiān)控過程
Druid高性能數(shù)據(jù)庫連接池與SpringBoot結(jié)合使用,顯著提升數(shù)據(jù)訪問性能,通過內(nèi)置監(jiān)控頁面實時查看連接狀態(tài)、SQL執(zhí)行情況等關(guān)鍵信息2026-06-06
Java?ArrayList遍歷foreach與iterator時remove的區(qū)別
這篇文章主要介紹了Java?ArrayList遍歷foreach與iterator時remove的區(qū)別,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下2022-07-07
SpringCloud整合Netty集群實現(xiàn)WebSocket的示例代碼
文章主要介紹了SpringCloud整合Netty集群實現(xiàn)WebSocket的相關(guān)內(nèi)容,包括服務注冊和發(fā)現(xiàn)中心的配置,如使用Nacos、CommandLineRunner啟動Netty服務等,還介紹了通過Redis實現(xiàn)消息發(fā)布訂閱的機制,需要的朋友可以參考下2024-11-11
Java實現(xiàn)線程按序交替執(zhí)行的方法詳解
這篇文章主要為大家詳細介紹了Java如何實現(xiàn)線程按序交替執(zhí)行,文中的示例代碼講解詳細,對我們了解線程有一定幫助,需要的可以參考一下2022-10-10

