詳解Spring中REQUIRED事務(wù)的回滾機制詳解
在 Spring 的事務(wù)管理中,REQUIRED 是最常用也是默認的事務(wù)傳播屬性。很多開發(fā)者在使用時會遇到一個常見的困惑:為什么內(nèi)部方法拋出的異常即便被外層捕獲了,事務(wù)還是會整體回滾? 本文將深入剖析 REQUIRED 下的事務(wù)回滾機制及其背后的原理。
1. REQUIRED 的定義
- 默認傳播屬性。
- 如果當前存在事務(wù):加入當前事務(wù)。
- 如果沒有事務(wù):創(chuàng)建一個新事務(wù)。
這意味著調(diào)用鏈上的所有方法都運行在同一個物理事務(wù)里,彼此之間沒有隔離。只要其中一個方法觸發(fā)回滾條件,整個事務(wù)都會被撤銷。
2. REQUIRED 下的回滾機制
2.1 異常觸發(fā)回滾
Spring 默認回滾規(guī)則:
- 運行時異常(
RuntimeException)和錯誤(Error):觸發(fā)回滾。 - 受檢異常(
CheckedException):不會觸發(fā)回滾,除非在@Transactional(rollbackFor = Exception.class)中顯式指定。
2.2 回滾狀態(tài)傳播
假設(shè)調(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)建事務(wù)。inner()加入同一事務(wù)并拋出異常。- Spring 的事務(wù)攔截器捕獲異常 → 標記當前事務(wù)為 rollback-only。
- 即便外層
outer()捕獲了異常,rollback-only 標記不會自動清除。 - 最終事務(wù)提交時,Spring 檢查到 rollback-only → 調(diào)用
rollback()而不是commit()。
因此,捕獲異常并不能阻止事務(wù)回滾。
3. 為什么捕獲異常也會回滾?
原因在于 Spring 的事務(wù)是基于 事務(wù)狀態(tài)標記 而不是你的 try-catch 來決定的:
- 方法拋出異常 →
TransactionInterceptor判斷是否需要回滾。 - 如果符合規(guī)則 →
status.setRollbackOnly()。 - 外層即便捕獲異常,也只是業(yè)務(wù)層邏輯“消化”了異常,但事務(wù)狀態(tài)已經(jīng)不可提交。
最終由事務(wù)管理器在 commit() 階段檢查 rollback-only 標記,決定整體回滾。
4. 如何避免“誤回滾”?
如果確實需要內(nèi)部異常不影響外部事務(wù),可以考慮以下方式:
4.1 修改回滾規(guī)則
@Transactional(noRollbackFor = RuntimeException.class)
public void inner() {
throw new RuntimeException("不會觸發(fā)回滾");
}
但這種方式風險極高,可能提交錯誤數(shù)據(jù)。
4.2 手動清理事務(wù)狀態(tài)(不推薦)
catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(false);
}
此方式非常危險,通常不建議。
4.3 使用其他傳播屬性(推薦)
- REQUIRES_NEW:為內(nèi)部方法開啟新事務(wù),失敗只影響內(nèi)部,不影響外部。
- NESTED:使用保存點,內(nèi)部失敗可回滾到保存點,外部事務(wù)繼續(xù)。
這兩種方式才是更優(yōu)雅的解決方案。
5. Spring 內(nèi)部執(zhí)行流程
核心邏輯在 TransactionAspectSupport.invokeWithinTransaction():
- 獲取或創(chuàng)建事務(wù)。
- 執(zhí)行目標方法。
- 捕獲異常 → 判斷是否需要回滾 → 設(shè)置 rollback-only。
- 方法結(jié)束 → 根據(jù)狀態(tài)決定
commit()還是rollback()。
6. 總結(jié)
REQUIRED下,所有方法共享一個事務(wù)。- 任意方法異常觸發(fā) rollback-only → 整體回滾。
- 捕獲異常≠事務(wù)安全,Spring 根據(jù)事務(wù)狀態(tài)決定提交還是回滾。
- 如果需要更細粒度的控制,應使用
REQUIRES_NEW或NESTED。
一句話總結(jié):在 Spring 的 REQUIRED 模式下,事務(wù)是一榮俱榮、一損俱損的整體,內(nèi)部異常即便被捕獲也會讓整個事務(wù)回滾,真正想做到“局部回滾”需要換傳播屬性來實現(xiàn)。
到此這篇關(guān)于詳解Spring中REQUIRED事務(wù)的回滾機制詳解的文章就介紹到這了,更多相關(guān)Spring REQUIRED 事務(wù)回滾內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SparkSQL使用IDEA快速入門DataFrame與DataSet的完美教程
本文給大家介紹使用idea開發(fā)Spark SQL 的詳細過程,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-08-08
SpringBoot+MyBatis-Plus實現(xiàn)數(shù)據(jù)庫讀寫分離的代碼示例
在當今互聯(lián)網(wǎng)應用中,數(shù)據(jù)庫讀寫分離是提高系統(tǒng)性能和穩(wěn)定性的重要手段之一,通過將讀操作和寫操作分別路由到不同的數(shù)據(jù)庫節(jié)點,可以有效減輕數(shù)據(jù)庫服務(wù)器的負擔,本文將介紹如何利用SpringBoot和MyBatis-Plus框架實現(xiàn)數(shù)據(jù)庫讀寫分離,需要的朋友可以參考下2023-11-11
在Java8與Java7中HashMap源碼實現(xiàn)的對比
這篇文章主要介紹了在Java8與Java7中HashMap源碼實現(xiàn)的對比,內(nèi)容包括HashMap 的原理簡單介紹、結(jié)合源碼在Java7中是如何解決hash沖突的以及優(yōu)缺點,結(jié)合源碼以及在Java8中如何解決hash沖突,balance tree相關(guān)源碼介紹,需要的朋友可以參考借鑒。2017-01-01
基于RocketMQ實現(xiàn)分布式事務(wù)的方法
了保證系統(tǒng)數(shù)據(jù)的一致性,我們需要確保這些服務(wù)中的操作要么全部成功,要么全部失敗,通過使用RocketMQ實現(xiàn)分布式事務(wù),我們可以協(xié)調(diào)這些服務(wù)的操作,保證數(shù)據(jù)的一致性,這篇文章主要介紹了基于RocketMQ實現(xiàn)分布式事務(wù),需要的朋友可以參考下2024-03-03

