Spring 事務的底層原理常見陷阱

一、Spring 事務的底層原理

1. 核心機制
  • 動態代理(AOP)
    Spring 通過動態代理(JDK 或 CGLIB)生成代理對象,攔截被 @Transactional 注解標記的方法。
  • 事務攔截器
    TransactionInterceptor 負責管理事務的生命周期(開啟、提交、回滾)。
  • 事務管理器
    PlatformTransactionManager 實現類(如 DataSourceTransactionManager)負責底層事務操作(如 JDBC 的 commit())。
  • 線程綁定
    通過 ThreadLocalTransactionSynchronizationManager)存儲當前事務的數據庫連接,確保同一線程內多個操作共享同一事務。
2. 關鍵流程

// 偽代碼:事務攔截器邏輯
public Object invoke(MethodInvocation invocation) {
// 1. 獲取事務屬性(@Transactional配置)
TransactionAttribute txAttr = getTransactionAttribute(invocation.getMethod());

// 2. 獲取事務管理器
PlatformTransactionManager tm = determineTransactionManager(txAttr);// 3. 開啟事務(根據傳播行為決定是否新建事務)
TransactionStatus status = tm.getTransaction(txAttr);try {// 4. 執行目標方法Object result = invocation.proceed();// 5. 提交事務tm.commit(status);return result;
} catch (Exception ex) {// 6. 回滾事務(根據rollbackFor規則)completeTransactionAfterThrowing(txAttr, status, ex);throw ex;
}

}


二、常見陷阱及代碼示例

陷阱 1:自調用導致事務失效

問題:同類內部方法調用(未經過代理對象),事務注解失效。

@Service
public class UserService {
public void createUser() {
// 直接調用內部方法,事務不生效!
this.insertUser();
}

@Transactional
public void insertUser() {// 插入用戶到數據庫
}

}

原因this.insertUser() 是目標對象直接調用,未經過代理對象,事務攔截器未被觸發。

解決

  • 方法 1:注入自身代理對象(通過 AopContext):

@EnableAspectJAutoProxy(exposeProxy = true) // 啟動類開啟暴露代理
public class UserService {
public void createUser() {
UserService proxy = (UserService) AopContext.currentProxy();
proxy.insertUser(); // 通過代理對象調用
}
}

  • 方法 2:拆分類,將 insertUser 放到另一個 Bean 中。

陷阱 2:異常被捕獲未拋出

問題:事務方法中捕獲異常但未重新拋出,導致事務無法回滾。

@Transactional
public void updateUser() {
try {
userDao.update(user); // 可能拋出SQLException
} catch (SQLException e) {
// 捕獲異常但未拋出,事務不會回滾!
log.error(“更新失敗”, e);
}
}

原因:Spring 默認只對 RuntimeExceptionError 回滾,且必須拋出異常。

解決

  • 方法 1:拋出 RuntimeException

catch (SQLException e) {
throw new RuntimeException(“更新失敗”, e); // 觸發回滾
}

  • 方法 2:配置 @Transactional(rollbackFor = SQLException.class)

陷阱 3:事務傳播行為誤解

問題:嵌套事務未按預期回滾。

@Transactional
public void outerMethod() {
userDao.insertUser();
try {
innerService.innerMethod();
} catch (Exception e) {
// 期望 innerMethod 回滾,但 outerMethod 繼續提交
}
}

@Service
public class InnerService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
userDao.updateUser(); // 拋出異常
}
}

現象:如果 innerMethod 拋出異常,innerMethod 的事務會回滾,但 outerMethod 的事務仍會提交(因為 innerMethod 的事務是獨立的)。

解決

  • 如果希望 outerMethodinnerMethod 失敗時整體回滾,需在 outerMethod 中不捕獲異常,或重新拋出異常。

陷阱 4:數據庫引擎不支持事務

問題:使用 MyISAM 引擎的 MySQL 表不支持事務。

CREATE TABLE user (
id INT PRIMARY KEY
) ENGINE=MyISAM; – 不支持事務

現象:即使代碼正確配置事務,操作仍不會回滾。

解決:使用 InnoDB 引擎:

CREATE TABLE user (…) ENGINE=InnoDB;


陷阱 5:非 public 方法事務失效

問題@Transactional 標記在非 public 方法上,事務不生效。

@Service
public class UserService {
@Transactional
private void internalUpdate() { // 非 public 方法!
userDao.update(user);
}
}

原因:Spring 默認通過代理實現 AOP,無法攔截 private/protected 方法。

解決

  • 將方法改為 public
  • 使用 AspectJ 模式(配置 @EnableTransactionManagement(mode = AdviceMode.ASPECTJ))。

陷阱 6:多線程下事務上下文丟失

問題:新線程無法繼承原線程的事務上下文。

@Transactional
public void process() {
new Thread(() -> {
userDao.updateUser(); // 新線程無法共享事務
}).start();
}

原因TransactionSynchronizationManager 使用 ThreadLocal,不同線程無法共享事務資源。

解決

  • 避免在事務方法中啟動新線程操作數據庫。
  • 使用編程式事務管理(手動控制事務邊界)。

三、總結

關鍵點
  1. 動態代理 + 事務管理器 + ThreadLocal 是 Spring 事務的核心。
  2. 自調用、異常處理、傳播行為、數據庫支持 是常見陷阱。
  3. 通過代碼審查、日志(如 AbstractPlatformTransactionManagerDEBUG 日志)排查問題。
最佳實踐
  • 使用 @Transactional 時明確指定 rollbackFor
  • 避免同類自調用(通過代理對象或拆分類)。
  • 確保數據庫引擎支持事務(如 InnoDB)。
  • 事務方法保持 public 修飾符。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78271.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78271.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78271.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java SE(6)——類和對象(一)

1.初始面向對象 1.1 什么是面向對象 Java是一門純面向對象的編程語言(Object Oriented Program,簡稱OOP),在面向對象的世界里,一切皆為對象。面向對象是解決問題的一種思想,主要依靠對象之間的交換來完成一件事情 1.2 面向過程…

cpp細碎知識點

1 重寫 (Override): 派生類中定義一個與基類虛函數具有相同函數簽名(函數名、參數列表、返回類型)的函數,這被稱為重寫。 重寫意味著派生類提供了基類虛函數的一個特定于派生類的實現。 重寫是實現多態的關鍵 2 虛基類 (Virtual Base Class…

若依 FastAPI + Vue3 項目 Docker 部署筆記( 啟動器打包教程)

本文記錄了將 start.bat 打包成 .exe 啟動器的詳細教程,適合項目交付或導師演示用。 🧭 一、如何將 start.bat 打包為啟動器 .exe(含圖標 自動打開瀏覽器) ? 1. 創建三大功能腳本 start.bat → 啟動項目(docke…

基于springboot的金院銀行廳預約系統的設計及實現(源碼+lw+部署文檔+講解),源碼可白嫖!

摘要 隨著信息技術在管理上越來越深入而廣泛的應用,信息管理系統的實施在技術上已逐步成熟。信息管理系統是一個不斷發展的新型學科,任何一個單位要生存要發展,要高效率地把內部活動有機地組織起來,就必須建立與自身特點相適應的…

創意控制臺:下雨動畫特效(ASCII 雨滴下落)

在編程的世界里,控制臺不僅僅是輸出文本信息的工具,通過巧妙的代碼設計,我們還能在其中創造出充滿趣味的動態畫面。本文將帶領大家使用 C 語言打造一個創意控制臺下雨動畫特效,利用 ASCII 字符模擬雨滴下落的過程,為單…

MySQL--索引入門

MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構。 Mysql在存儲數據之外,數據庫系統各種還維護著滿足特定查找算法的數據結構,這些數據結構以某種引用(指向)表中的數據…

MIT XV6 - 1.2 Lab: Xv6 and Unix utilities - pingpong

接上文 MIT XV6 - 1.1 Lab: Xv6 and Unix utilities - user/_sleep 是什么?做什么? pingpong 不務正業了那么久(然而并沒有,雖然還在探索sleep,但是教材我已經看完了前三章了),讓我們趕緊繼續下去 在進行本實驗之前請務…

前端面經-VUE3篇(二)--vue3組件知識(一)組件注冊、props 與 emits、透傳、插槽(Slot)

組件允許我們將 UI 劃分為獨立的、可重用的部分,并且可以對每個部分進行單獨的思考。在實際應用中,組件常常被組織成一個層層嵌套的樹狀結構: 一、注冊 Vue 組件本質上是一個可以復用的 自定義 HTML 元素,為了在其他組件中使用一…

LeetCode —— 102. 二叉樹的層序遍歷

😶?🌫?😶?🌫?😶?🌫?😶?🌫?Take your time ! 😶?🌫?😶?🌫?😶?🌫?😶?🌫?…

Linux第20節 --- inode和文件系統

一、沒有被打開的文件 如果一個文件沒有被打開,那么該文件存儲在哪里? 該文件是存儲在磁盤當中的! 文件 文件內容 文件屬性! 文件的內容是按照數據塊存儲的;文件的屬性其實就是inode(是一個128字節的…

1.PowerBi保姆級安裝教程

1.進入power bi網站 PowerBi下載鏈接 2.下載power bi軟件 3.雙擊安裝 4.下一步 5.下一步 6.下一步 7.下一步 8.安裝 9.雙擊桌面圖標

Android Studio中OpenCV應用詳解:圖像處理、顏色對比與OCR識別

文章目錄 一、OpenCV在Android中的集成與配置1.1 OpenCV簡介1.2 在Android Studio中集成OpenCV1.2.1 通過Gradle依賴集成1.2.2 通過模塊方式集成1.2.3 初始化OpenCV 1.3 OpenCV基礎類介紹 二、指定區域圖像抓取與對比2.1 圖像抓取基礎2.2 指定區域圖像抓取實現2.2.1 從Bitmap中…

前端面試每日三題 - Day 22

今天我們將深入探討 JavaScript 中的 Set 和 Map 數據結構,了解它們的特性及應用場景。接下來,我們會分析 React 的 Suspense 和 Concurrent Mode 的工作原理,探索它們如何提升應用的性能和用戶體驗。最后,我們將學習如何設計一個…

[Vue]編程式導航

在 Vue 中&#xff0c;編程式導航是通過 JavaScript 代碼&#xff08;而非 <router-link> 標簽&#xff09;動態控制路由跳轉的核心方式。這個方法依賴于 Vue Router 提供的 API&#xff0c;能更靈活地處理復雜場景&#xff08;如異步操作、條件跳轉等&#xff09;。 一、…

鄒曉輝教授十余年前關于圍棋程序與融智學的思考,體現了對復雜系統本質的深刻洞察,其觀點在人工智能發展歷程中具有前瞻性意義。我們可以從以下三個維度進行深入解析:

鄒曉輝教授十余年前關于圍棋程序與融智學的思考&#xff0c;體現了對復雜系統本質的深刻洞察&#xff0c;其觀點在人工智能發展歷程中具有前瞻性意義。我們可以從以下三個維度進行深入解析&#xff1a; 一、圍棋程序的二元解構&#xff1a;數據結構與算法的辯證關系 1.1.形式…

The Traitor King (10 player 25 player)

The Traitor King 十字軍試煉尾王成就。叛變的國王&#xff1a;在30秒內殺死40只蟲群甲蟲。考驗團隊配合的成就。比不朽者&#xff0c;黑曜石31等等強度大&#xff0c;甚至感覺比寶庫地風火難。

數據結構一 單鏈表

1.單鏈表 1.數據結構簡介 程序數據結構算法 數據 數據&#xff08;data&#xff09;是客觀事物的一個符號表示 數據元素&#xff08;data element&#xff09;是數據的基本單位&#xff0c;一 個數據元素可以由若干個數據項&#xff08;data item&#xff09;組成。數據項…

GPU集群監控系統開發實錄:基于Prometheus+Grafana的算力利用率可視化方案

一、科研場景下的GPU監控痛點 在深度學習模型訓練、分子動力學模擬等科研場景中&#xff0c;GPU集群的算力利用率直接影響著科研效率。筆者在參與某高校計算中心的運維工作時&#xff0c;發現以下典型問題&#xff1a; 資源黑洞現象&#xff1a;多課題組共享GPU時出現"搶…

【計算機視覺】三維重建: MVSNet:基于深度學習的多視圖立體視覺重建框架

MVSNet&#xff1a;基于深度學習的多視圖立體視覺重建框架 技術架構與核心算法1. 算法流程2. 關鍵創新 環境配置與實戰指南硬件要求安裝步驟數據準備&#xff08;DTU數據集&#xff09; 實戰流程1. 模型訓練2. 深度圖推斷3. 點云生成 常見問題與解決方案1. CUDA內存不足2. 特征…

智能家居的OneNet云平臺

一、聲明 該項目只需要創建一個產品&#xff0c;然后這個產品里面包含幾個設備&#xff0c;而不是直接創建幾個產品 注意&#xff1a;傳輸數據使用到了不同的power&#xff0c;還有一定要手機先聯網才能使用云平臺 二、OneNet云平臺創建 &#xff08;1&#xff09;Temperatur…