Spring Boot 事務失效問題詳解:原因、場景與解決方案

在 Spring Boot 開發中,事務管理是保證數據一致性和完整性的核心機制。然而,許多開發者在使用 @Transactional 注解時,可能會遇到事務失效的問題,導致數據異常或業務邏輯錯誤。本文將深入分析 Spring Boot 中事務失效的常見原因,并結合實際場景給出解決方案,幫助大家更好地掌握事務的使用。

一、事務失效的常見場景

1.1 同類中方法直接調用導致事務失效

原因分析

Spring 的事務是通過 AOP 代理實現的,只有通過代理對象調用的方法,事務才會生效。如果在同一個類中,一個方法直接調用另一個帶有 @Transactional 注解的方法(即 this.method() 方式),則事務不會生效。

示例代碼

@Service
public class UserService {@Transactionalpublic void createUser(User user) {// 保存用戶}public void createUserAndLog(User user) {this.createUser(user); // 事務失效log.info("用戶創建成功");}
}

解決方案

  • 將事務方法提取到另一個類中,通過 Spring 注入調用。
  • 使用 AopContext.currentProxy() 獲取當前代理對象調用方法。
  • 自我注入:將當前 Service 注入到自身,通過注入的對象調用方法。

推薦方式(自我注入)

@Service
public class UserService {@Autowiredprivate UserService self; // 自我注入@Transactionalpublic void createUser(User user) {// 保存用戶}public void createUserAndLog(User user) {self.createUser(user); // 事務生效log.info("用戶創建成功");}
}

1.2 異常未被正確捕獲或拋出

原因分析

默認情況下,Spring 只對 RuntimeException 和 Error 進行回滾。如果捕獲了異常但未拋出,或拋出了非運行時異常,事務不會回滾。

示例代碼

@Transactional
public void updateUser(User user) {try {userRepository.save(user);} catch (Exception e) {log.error("更新失敗", e);// 異常被吞掉,事務不會回滾}
}

解決方案

  • @Transactional 注解中指定回滾的異常類型。
  • 捕獲異常后,重新拋出 RuntimeException。

推薦方式

@Transactional(rollbackFor = Exception.class)
public void updateUser(User user) {try {userRepository.save(user);} catch (Exception e) {log.error("更新失敗", e);throw new RuntimeException("更新失敗", e);}
}

1.3 事務傳播行為配置不當

原因分析

在嵌套事務中,如果內層事務使用了 Propagation.REQUIRES_NEW,它會啟動一個獨立的新事務,外層事務的回滾不會影響內層事務,可能導致數據不一致。

示例代碼

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {// 內層事務
}@Transactional
public void outerMethod() {innerMethod();throw new RuntimeException("外層異常");
}

問題

  • 外層事務回滾,但內層事務已提交,導致數據不一致。

解決方案

  • 根據業務需求選擇合適的傳播行為。
  • 如果希望內外事務一致,避免使用 REQUIRES_NEW,改用 REQUIRED

推薦方式

@Transactional(propagation = Propagation.REQUIRED)
public void innerMethod() {// 內層事務
}@Transactional
public void outerMethod() {innerMethod();throw new RuntimeException("外層異常");
}

1.4 數據庫引擎不支持事務

原因分析

某些數據庫引擎(如 MySQL 的 MyISAM)不支持事務,即使代碼中配置了事務,也不會生效。

解決方案

  • 確保數據庫使用支持事務的引擎,如 InnoDB

1.5 事務管理器未正確配置

原因分析

如果項目中沒有正確配置事務管理器,@Transactional 注解不會生效。

解決方案

  • 確保在配置類中配置了事務管理器,例如:
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);
}

1.6 多數據源事務管理問題

原因分析

在多數據源場景下,如果沒有為每個數據源配置獨立的事務管理器,事務可能會失效。

解決方案

  • 為每個數據源配置獨立的事務管理器。
  • 使用 @Transactional(value = "transactionManagerName") 指定事務管理器。

二、如何排查事務失效問題

2.1 啟用事務日志

application.properties 中開啟事務日志:

logging.level.org.springframework.transaction=DEBUG
logging.level.org.springframework.jdbc=DEBUG

2.2 檢查代理對象

確保事務方法是通過 Spring 的代理對象調用的,而不是直接調用。

2.3 檢查異常處理

確保異常被正確拋出,并符合事務回滾的條件。

2.4 檢查數據庫引擎

確保數據庫引擎支持事務,例如使用 InnoDB。


三、事務傳播行為(Propagation)的常用類型

傳播行為類型說明
REQUIRED(默認)當前方法加入已有事務,若沒有則創建新事務。
REQUIRES_NEW創建新事務,并掛起當前事務。
NOT_SUPPORTED不支持事務,掛起當前事務。
NEVER不允許事務,若當前有事務則拋出異常。
SUPPORTS當前方法可以在事務中執行,也可以不在事務中執行。
MANDATORY當前方法必須在事務中執行,若沒有事務則拋出異常。

四、總結

Spring Boot 中的事務失效問題,通常是由于以下原因導致的:

  • 同類中方法直接調用
  • 異常未被正確拋出
  • 事務傳播行為配置不當
  • 數據庫引擎不支持事務
  • 事務管理器未正確配置
  • 多數據源事務管理問題

為了避免事務失效,建議遵循以下最佳實踐:

  • 確保事務方法通過 Spring 代理調用
  • 正確處理異常,確保事務回滾
  • 合理配置事務傳播行為
  • 使用支持事務的數據庫引擎
  • 正確配置事務管理器

通過本文的分析和解決方案,相信大家對 Spring Boot 的事務管理有了更深入的理解。在實際開發中,合理使用事務,能夠有效保證數據的一致性和完整性。

參考資料

  • Spring 官方文檔 - 事務管理
  • CSDN - SpringBoot的事務失效

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

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

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

相關文章

Python-文件操作-StringIO和BytesIO-路徑操作-shutil模塊-csv,ini序列化和反序列化-argparse使用-學習筆記

序 欠4年前的一份學習筆記,獻給今后的自己。 文件操作 馮諾依曼體系架構CPU由運算器和控制器組成 運算器,完成各種算數運算、邏輯運算、數據傳輸等數據加工處理 。 控制器,控制程序的執行 存儲器,用于記憶程序和數據,例…

LLM的表征做減法的是什么,自然語言是一個矩陣,怎么進行減法的

LLM的表征做減法的是什么,自然語言是一個矩陣,怎么進行減法的 有個假設:就是最后一個詞語融合了前面詞語的信息 減法操作主要用于提取模型內部表征中的"誠實性"概念向量。具體來說,這是通過對比誠實和不誠實場景下的模型隱藏狀態實現的。 import torch from t…

Java創建型模式---單例模式

單例模式基礎概念單例模式是一種創建型設計模式,其核心思想是確保一個類僅有一個實例,并提供一個全局訪問點來獲取這個實例。在 Java 中實現單例模式主要有以下關鍵點:私有構造函數 - 防止外部通過new關鍵字創建實例靜態實例變量 - 類內部持有…

詳解Kafka重平衡機制詳解

Kafka 的重平衡機制(Rebalance)是確保消費者組內成員動態變化(如新成員加入、現有成員退出或崩潰、訂閱主題分區數變化)時,分區所有權能合理、公平地重新分配的核心機制。其目標是保證所有分區都有消費者處理&#xff…

代碼詳細注釋:文件IO在用戶管理系統中的應用實踐:C語言實現用戶名查重與密碼確認與支持日志記錄的終端用戶認證解決方案的注冊登錄系統

代碼/* 作業增強版注冊登錄系統 - 帶日志和安全性增強功能 */ #include <stdio.h> // 標準輸入輸出函數(printf, scanf等) #include <stdlib.h> // 標準庫函數(exit, malloc等) #include <string.h> // 字符串處理函數(strcmp, strcspn等) #inc…

Go與JS無縫協作:Goja引擎實戰之錯誤處理最佳實踐

引言&#xff1a;當Go邂逅JavaScript 在現代軟件開發中&#xff0c;跨語言協作已成為提升效率的關鍵。想象一下&#xff1a;用Go的高性能處理核心邏輯&#xff0c;同時用JavaScript的靈活性實現動態規則——這不再是夢想。Goja&#xff0c;這個純Go語言實現的JavaScript引擎&am…

繼承與多態:面向對象編程的兩大支柱

引言&#xff1a;為什么必須掌握繼承與多態&#xff1f; 在Java開發中&#xff0c;繼承與多態是構建可擴展、易維護系統的基石&#xff1a; 繼承&#xff1a;實現代碼復用&#xff0c;建立清晰的類層次結構多態&#xff1a;提升代碼靈活性&#xff0c;實現"編寫一次&#…

2025使用VM虛擬機安裝配置Macos蘋果系統下Flutter開發環境保姆級教程--上篇

前言 我們在學習Flutter開發的過程中&#xff0c;永遠都跳不過去的一個問題就是如何在MAC下開發并打包Flutter工程項目&#xff0c;但MAC開發首先要解決的問題就是我們一般技術人員的電腦都是WINDOWS操作系統&#xff0c;專門配置一臺MAC的話成本又是不得不考慮的因素&#xf…

250708-Svelte項目從Debian遷移到無法聯網的RHEL全流程指南

&#x1f4cc; 背景 在 Debian 上使用以下命令創建了一個 Svelte 項目&#xff1a; npm install -g sv npx sv create my-svelte-demo cd my-svelte-demo npm install npm run dev現在需要將該項目遷移到一臺 無法聯網的 RHEL 9.4 服務器 上運行&#xff0c;出現如下報錯&…

力扣 hot100 Day39

118. 楊輝三角 給定一個非負整數 numRows&#xff0c;生成「楊輝三角」的前 numRows 行。 class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>> res(numRows);for (int i 0; i < numRows; i) {res[i].resi…

HuggingFists: 無代碼處理復雜PDF

有過使用LLM搭建RAG或其它類知識系統的朋友一定會對文檔數據的復雜多樣性有著深刻的理解。各行各業的磁盤中都沉睡了數年到數十年的各類文檔信息&#xff0c;包括&#xff1a;Doc、Docx、PPT、PDF、XLS、PNG、JPEG等各類格式。利用LLM激活這些數據價值的首要工作就是能夠正確的…

Vue 3 框架實現理念、架構與設計哲學深度解析

第一部分&#xff1a;Vue 3 的起源&#xff1a;架構演進與設計哲學 Vue 3 的誕生并非一次簡單的版本迭代&#xff0c;而是一場深刻的架構革命。它的出現是前端技術演進、應用規模擴張以及對更高性能和可維護性追求的必然結果。要全面理解 Vue 3 的各項實現理念&#xff0c;必須…

SQL Server使用存儲過程導出數據到Excel實現方式

在SQL Server數據庫管理中,存儲過程作為預編譯的T-SQL語句集合,能顯著提升數據操作效率與安全性。將數據導出到Excel的需求廣泛存在于報表生成、數據遷移等場景。本文詳細解析四種通過存儲過程實現數據導出的技術方案,涵蓋代碼實現、適用場景及優化策略,為不同業務需求提供…

OpenGL 2. 著色器

#include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include <stdexcept>// 函數聲明 void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow* window); void checkShaderCom…

【c++】容器擴容導致的類實例資源被錯誤釋放

BUG記錄 表現為新實例被存入前&#xff0c;容器內部的舊實例的析構被意外調用 因為 std::vector 在容量不足時&#xff0c;會自動擴容&#xff0c;把舊元素「搬」到新內存&#xff0c;然后析構舊內存上的那些對象。然后由于LKMotorController 類里沒有正確處理移動語義&#xf…

TypeScript 集成

下面&#xff0c;我們來系統的梳理關于 Vue TypeScript 深度集成 的基本知識點&#xff1a;一、TypeScript 與 Vue 集成概述 1.1 為什么需要 TypeScript 類型安全&#xff1a;編譯時類型檢查&#xff0c;減少運行時錯誤代碼智能&#xff1a;強大的IDE智能提示和自動補全可維護…

npm proxy

背景 前端項目下載依賴時經常會出現timeout的情況&#xff0c;此時有三種解決方案。 切換鏡像源。 適用于對依賴版本要求不嚴格的情況。延長超時時間。設置npm proxy。一些生產環境對依賴版本有著嚴格要求&#xff0c;并且指定了依賴的下載地址&#xff08;如下圖&#xff09;&…

TVS管工作原理是什么?主要的應用場景都有哪些?

什么是TVS管&#xff1f; TVS&#xff08;Transient Voltage Suppressors&#xff09;&#xff0c;即瞬態電壓抑制器&#xff0c;也被稱為雪崩擊穿二極管&#xff0c;是一種二極管形式的高效能保護器件&#xff0c;常用來防止端口瞬間的電壓沖擊造成后級電路的損壞。 TVS 有單…

分布式微服務系統架構第156集:JavaPlus技術文檔平臺日更-Java線程池使用指南

title: java線程池使用 author: 哪吒 date: 2023-06-15點擊勘誤issues&#xff0c;哪吒感謝大家的閱讀Java線程池使用指南1. 線程池基礎使用1.1 創建線程池的方式方式一&#xff1a;使用Executors工具類&#xff08;不推薦&#xff09;// 1. 固定大小線程池 ExecutorService fi…

【最新版】點大全能版v2.6.7.1 含匯付斗拱插件+uniapp前端

一.介紹V2全能版本、獨立版本全開源&#xff0c;含鏈動21&#xff0c;匯付斗拱?、排隊免單、推三返1 &#xff0c;扶持金&#xff0c;平級獎&#xff0c;團隊業績獎&#xff0c;酒店管理&#xff0c;約車&#xff0c;餐飲等眾多營銷功能&#xff0c;商城系統版本號為2.6.7.1&a…