SpringBoot事務(wù)失效的八大原因及解決方案
引言
在 Spring Boot 項(xiàng)目開發(fā)中,聲明式事務(wù)管理通過 @Transactional 注解提供了極大的便利。
但許多開發(fā)者都曾遇到過事務(wù)不生效的困擾。
本文將詳細(xì)分析導(dǎo)致 Spring Boot 事務(wù)失效的八大常見情況,并提供相應(yīng)的解決方案。
1. 數(shù)據(jù)庫引擎不支持事務(wù)
問題分析:這是最根本的原因。如果數(shù)據(jù)庫存儲引擎本身不支持事務(wù)(如 MySQL 的 MyISAM),那么無論 Spring 如何配置,事務(wù)都不會生效。
解決方案:
- 確保你的數(shù)據(jù)庫表使用支持事務(wù)的引擎,如 MySQL 的 InnoDB
- 建表時(shí)指定存儲引擎:
CREATE TABLE ... ENGINE=InnoDB;
2. 事務(wù)方法非 public 修飾
問題分析:@Transactional 基于 Spring AOP 實(shí)現(xiàn),而 AOP 代理默認(rèn)無法攔截非 public 方法。
@Service
public class UserService {
@Transactional // 失效!
private void createUser(User user) {
userMapper.insert(user);
}
}解決方案:
- 始終將
@Transactional注解應(yīng)用于 public 方法上
3. 自調(diào)用問題(Within-Class Invocation)
問題分析:這是最常見且最容易踩坑的原因。當(dāng)一個(gè)類中的非事務(wù)方法調(diào)用同一個(gè)類中的 @Transactional 方法時(shí),事務(wù)不會生效。
@Service
public class UserService {
public void createUser(User user) {
// 一些非事務(wù)操作
this.insertUser(user); // 自調(diào)用,事務(wù)失效!
}
@Transactional
public void insertUser(User user) {
userMapper.insert(user);
// 如果這里出現(xiàn)異常,事務(wù)不會回滾
}
}解決方案:
- 推薦方案:將事務(wù)方法抽取到另一個(gè) Service 類中
- 通過 ApplicationContext 獲取代理對象調(diào)用(不優(yōu)雅)
- 使用 AspectJ 模式的事務(wù)管理(配置復(fù)雜)
4. 異常類型不正確或被捕獲
問題分析:@Transactional 默認(rèn)只在拋出運(yùn)行時(shí)異常(RuntimeException)和 Error 時(shí)回滾。
@Transactional
public void method() throws Exception {
// 數(shù)據(jù)庫操作
throw new Exception("受檢異常"); // 事務(wù)不會回滾!
}另一個(gè)陷阱:異常被捕獲但未重新拋出
@Transactional
public void method() {
try {
int i = 1 / 0; // 拋出 RuntimeException
} catch (Exception e) {
e.printStackTrace(); // 只是打印,事務(wù)不會回滾!
}
}解決方案:
- 使用
rollbackFor屬性指定回滾的異常類型:
@Transactional(rollbackFor = Exception.class)
- 在 catch 塊中重新拋出運(yùn)行時(shí)異常
5. 傳播行為(Propagation)設(shè)置不當(dāng)
問題分析:錯(cuò)誤配置傳播行為會導(dǎo)致意外結(jié)果。
@Transactional(propagation = Propagation.NOT_SUPPORTED) // 不以事務(wù)運(yùn)行
public void method() {
// 這里沒有事務(wù)
}解決方案:
- 根據(jù)業(yè)務(wù)需求正確配置傳播行為
- 理解各種傳播行為的含義:
REQUIRED(默認(rèn)):支持當(dāng)前事務(wù),不存在則新建REQUIRES_NEW:新建事務(wù),掛起當(dāng)前事務(wù)NOT_SUPPORTED:非事務(wù)方式執(zhí)行NEVER:非事務(wù)方式執(zhí)行,存在事務(wù)則拋出異常
6. 未被 Spring 容器管理
問題分析:如果類沒有加上 @Service, @Component 等注解,它就不是 Spring Bean,其上的 @Transactional 注解不會被掃描。
// 缺少 @Service 注解
public class UserService {
@Transactional // 失效!
public void createUser(User user) {
// ...
}
}解決方案:
- 確保類被 Spring 管理,添加適當(dāng)?shù)淖⒔?/li>
7. 多線程環(huán)境下調(diào)用
問題分析:事務(wù)信息存儲在 ThreadLocal 中,新線程中的操作不屬于原事務(wù)。
@Transactional
public void method() {
new Thread(() -> {
userMapper.insert(user); // 不在事務(wù)中!
}).start();
}解決方案:
- 避免在事務(wù)方法中創(chuàng)建異步線程進(jìn)行數(shù)據(jù)庫操作
- 使用分布式事務(wù)解決方案處理跨線程事務(wù)
8. 配置問題
問題分析:
- 未開啟事務(wù)管理(雖然 Spring Boot 會自動配置)
- 多數(shù)據(jù)源未正確配置事務(wù)管理器
解決方案:
- 確保配置了
@EnableTransactionManagement(Spring Boot 通常自動配置) - 多數(shù)據(jù)源時(shí)為每個(gè)數(shù)據(jù)源配置對應(yīng)的事務(wù)管理器:
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}- 使用
@Transactional(value = "txManagerName")指定事務(wù)管理器
事務(wù)調(diào)試技巧
開啟事務(wù)調(diào)試日志,在 application.properties 中添加:
logging.level.org.springframework.transaction.interceptor=TRACE logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG
這將幫助你看清事務(wù)何時(shí)開啟、回滾或提交。
總結(jié)
Spring Boot 事務(wù)失效通常由以上八大原因?qū)е?,其中自調(diào)用問題最為常見。要確保事務(wù)正常工作,需要:
- 使用支持事務(wù)的數(shù)據(jù)庫引擎(如 InnoDB)
- 將
@Transactional應(yīng)用于 public 方法 - 避免自調(diào)用,將事務(wù)方法放在不同類中
- 正確處理異常,確保異常能夠觸發(fā)回滾
- 正確配置傳播行為
- 確保 Bean 被 Spring 管理
- 避免多線程事務(wù)問題
- 檢查事務(wù)相關(guān)配置
希望本文能幫助你有效解決 Spring Boot 中的事務(wù)失效問題。
以上就是SpringBoot事務(wù)失效的八大原因及解決方案的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot事務(wù)失效原因及解決的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于JSON.toJSONString()和Gson.toJson()方法的比較
本文介紹了兩種將Java對象轉(zhuǎn)換為JSON字符串的方法:阿里的`JSON.toJSONString()`和谷歌的`Gson.toJson()`,通過一個(gè)示例,展示了當(dāng)使用繼承關(guān)系且子類覆蓋父類字段時(shí),`Gson`會報(bào)錯(cuò),而`JSON`可以正常運(yùn)行,作者建議在處理JSON相關(guān)操作時(shí)使用阿里的`JSON`類2024-11-11
Java EasyExcel讀寫excel如何解決poi讀取大文件內(nèi)存溢出問題
這篇文章主要介紹了Java EasyExcel讀寫excel如何解決poi讀取大文件內(nèi)存溢出問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
Mybatis-Plus中分頁插件PaginationInterceptor的使用
我們在開發(fā)的過程中,經(jīng)常會遇到分頁操作,本文主要介紹了Mybatis-Plus中分頁插件PaginationInterceptor的使用,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Spring Boot 中整合 MyBatis-Plus詳細(xì)步驟(最新推薦)
本文詳細(xì)介紹了如何在SpringBoot項(xiàng)目中整合MyBatis-Plus,包括整合步驟、基本CRUD操作、分頁查詢、批量操作、自定義SQL操作等,通過這些步驟,開發(fā)者可以快速實(shí)現(xiàn)數(shù)據(jù)庫操作,提高開發(fā)效率,感興趣的朋友一起看看吧2025-01-01
Springboot-dubbo-fescar 阿里分布式事務(wù)的實(shí)現(xiàn)方法
這篇文章主要介紹了Springboot-dubbo-fescar 阿里分布式事務(wù)的實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-03-03
深入淺析Mybatis與Hibernate的區(qū)別與用途
這篇文章主要介紹了Mybatis與Hibernate的區(qū)別與用途的相關(guān)資料,需要的朋友可以參考下2017-10-10
IntelliJ IDEA 2017.1.4 x64配置步驟(介紹)
下面小編就為大家?guī)硪黄狪ntelliJ IDEA 2017.1.4 x64配置步驟(介紹)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
Java中Set與List的關(guān)系與區(qū)別介紹
這篇文章主要介紹了Java中Set與List的關(guān)系與區(qū)別介紹,本文總結(jié)它們兩個(gè)接口都是繼承自Collection、它們之間的存儲方式不一樣,需要的朋友可以參考下2015-03-03

