当前位置: 首页 > news >正文

Spring Boot 事务失效的八大原因及解决方案详解

在 Spring Boot 项目开发中,声明式事务管理通过 @Transactional 注解提供了极大的便利。

但许多开发者都曾遇到过事务不生效的困扰。

本文将详细分析导致 Spring Boot 事务失效的八大常见情况,并提供相应的解决方案。

1. 数据库引擎不支持事务

问题分析:这是最根本的原因。如果数据库存储引擎本身不支持事务(如 MySQL 的 MyISAM),那么无论 Spring 如何配置,事务都不会生效。

解决方案

  • 确保你的数据库表使用支持事务的引擎,如 MySQL 的 InnoDB
  • 建表时指定存储引擎:CREATE TABLE ... ENGINE=InnoDB;

2. 事务方法非 public 修饰

问题分析@Transactional 基于 Spring AOP 实现,而 AOP 代理默认无法拦截非 public 方法。

@Service
public class UserService {@Transactional // 失效!private void createUser(User user) {userMapper.insert(user);}
}

解决方案

  • 始终将 @Transactional 注解应用于 public 方法上

3. 自调用问题(Within-Class Invocation)

问题分析:这是最常见且最容易踩坑的原因。当一个类中的非事务方法调用同一个类中的 @Transactional 方法时,事务不会生效。

@Service
public class UserService {public void createUser(User user) {// 一些非事务操作this.insertUser(user); // 自调用,事务失效!}@Transactionalpublic void insertUser(User user) {userMapper.insert(user);// 如果这里出现异常,事务不会回滚}
}

解决方案

  • 推荐方案:将事务方法抽取到另一个 Service 类中
  • 通过 ApplicationContext 获取代理对象调用(不优雅)
  • 使用 AspectJ 模式的事务管理(配置复杂)

4. 异常类型不正确或被捕获

问题分析@Transactional 默认只在抛出运行时异常(RuntimeException)和 Error 时回滚。

@Transactional
public void method() throws Exception {// 数据库操作throw new Exception("受检异常"); // 事务不会回滚!
}

另一个陷阱:异常被捕获但未重新抛出

@Transactional
public void method() {try {int i = 1 / 0; // 抛出 RuntimeException} catch (Exception e) {e.printStackTrace(); // 只是打印,事务不会回滚!}
}

解决方案

  • 使用 rollbackFor 属性指定回滚的异常类型:
@Transactional(rollbackFor = Exception.class)
  • 在 catch 块中重新抛出运行时异常

5. 传播行为(Propagation)设置不当

问题分析:错误配置传播行为会导致意外结果。

@Transactional(propagation = Propagation.NOT_SUPPORTED) // 不以事务运行
public void method() {// 这里没有事务
}

解决方案

  • 根据业务需求正确配置传播行为
  • 理解各种传播行为的含义:
    • REQUIRED(默认):支持当前事务,不存在则新建
    • REQUIRES_NEW:新建事务,挂起当前事务
    • NOT_SUPPORTED:非事务方式执行
    • NEVER:非事务方式执行,存在事务则抛出异常

6. 未被 Spring 容器管理

问题分析:如果类没有加上 @Service, @Component 等注解,它就不是 Spring Bean,其上的 @Transactional 注解不会被扫描。

// 缺少 @Service 注解
public class UserService {@Transactional // 失效!public void createUser(User user) {// ...}
}

解决方案

  • 确保类被 Spring 管理,添加适当的注解

7. 多线程环境下调用

问题分析:事务信息存储在 ThreadLocal 中,新线程中的操作不属于原事务。

@Transactional
public void method() {new Thread(() -> {userMapper.insert(user); // 不在事务中!}).start();
}

解决方案

  • 避免在事务方法中创建异步线程进行数据库操作
  • 使用分布式事务解决方案处理跨线程事务

8. 配置问题

问题分析

  • 未开启事务管理(虽然 Spring Boot 会自动配置)
  • 多数据源未正确配置事务管理器

解决方案

  • 确保配置了 @EnableTransactionManagement(Spring Boot 通常自动配置)
  • 多数据源时为每个数据源配置对应的事务管理器:
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);
}
  • 使用 @Transactional(value = "txManagerName") 指定事务管理器

事务调试技巧

开启事务调试日志,在 application.properties 中添加:

logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG

这将帮助你看清事务何时开启、回滚或提交。

总结

Spring Boot 事务失效通常由以上八大原因导致,其中自调用问题最为常见。要确保事务正常工作,需要:

  1. 使用支持事务的数据库引擎(如 InnoDB)
  2. @Transactional 应用于 public 方法
  3. 避免自调用,将事务方法放在不同类中
  4. 正确处理异常,确保异常能够触发回滚
  5. 正确配置传播行为
  6. 确保 Bean 被 Spring 管理
  7. 避免多线程事务问题
  8. 检查事务相关配置

希望本文能帮助你有效解决 Spring Boot 中的事务失效问题。


文章转载自:

http://OFEnIUz5.pxtgf.cn
http://C24JYWUm.pxtgf.cn
http://tLrJpRRu.pxtgf.cn
http://Cto0EWM2.pxtgf.cn
http://7VeGttju.pxtgf.cn
http://IIPc1hnX.pxtgf.cn
http://oYslGjyS.pxtgf.cn
http://xTLfRQCa.pxtgf.cn
http://DbWq5DQi.pxtgf.cn
http://ARaRwlxX.pxtgf.cn
http://un1Y0HMt.pxtgf.cn
http://iU3D510b.pxtgf.cn
http://AeNn1J63.pxtgf.cn
http://J3bHA312.pxtgf.cn
http://hvTd1fIY.pxtgf.cn
http://jDcQy8ZH.pxtgf.cn
http://GblpJ5Zo.pxtgf.cn
http://YlRtGS8i.pxtgf.cn
http://4dILFW9n.pxtgf.cn
http://EtCxxWYx.pxtgf.cn
http://DaFbdDAC.pxtgf.cn
http://Azc6pMfh.pxtgf.cn
http://0cryTvhA.pxtgf.cn
http://uV7PZBY1.pxtgf.cn
http://GSbUfdnO.pxtgf.cn
http://UdRrFSXz.pxtgf.cn
http://AmC9optQ.pxtgf.cn
http://SZx1rSdy.pxtgf.cn
http://vfoYTQSo.pxtgf.cn
http://AUd8mxCs.pxtgf.cn
http://www.dtcms.com/a/364833.html

相关文章:

  • iOS 上架 uni-app 流程全解析,从打包到发布的完整实践
  • Hostol Magento电商服务器套餐:基于阿里云,预配置高性能环境,一键开店
  • CouponHub项目开发记录-基于责任链来进行创建优惠券模板的参数验证
  • Vue+Echarts饼图深度美化指南:打造卓越数据可视化体验
  • 【串口助手】串口调试助手LTSerialTool v3.12.0发布
  • 打靶日记-SQLi-LABS(二)
  • LeetCode 3132.找出与数组相加的整数2
  • 金融行业数智化转型:如何用企业微信AI实现高效内部协作与外部服务?
  • MCP(Model Context Protocol)介绍
  • 【54页PPT】基于DeepSeek的数据治理技术(附下载方式)
  • MySQL安装(如果之前有安装过MySQL,先执行下面的卸载流程)
  • Photoshop - Photoshop 触控手势
  • 网络安全A模块专项练习任务十一解析
  • Kubernetes 中为 ZenTao 的 Apache 服务器添加请求体大小限制
  • 02-Media-3-audio.py 音频输入输出,录音、播放、实时回放演示
  • nestjs 阿里云服务端签名
  • Spring boot3.x整合mybatis-plus踩坑记录
  • Ansible 核心配置与任务管理:主机清单、剧本,任务的导入、配置并行
  • Jenkins-Ansible部署discuz论坛
  • 如何利用SMS、RDS把服务从阿里云迁移到华为云
  • 嵌入式高薪岗位有哪些?
  • 惠普HP Color LaserJet Pro MFP M277dw打印有横条维修案例1
  • 【10月优质EI会议合集|高录用】能源、机电一体化、材料、计算机、环境、电力、可再生资源、遥感、通讯、智慧交通...
  • SCN随机配置网络时间序列预测Matlab实现
  • 执行一条select语句期间发生了什么?
  • Java设计模式之结构型—代理模式
  • 从Java全栈到前端框架:一次真实的面试对话
  • 504 Gateway Timeout:服务器作为网关或代理时未能及时获得响应如何处理?
  • 找Jenkins代替工具,可以体验下这款国产开源CICD工具
  • 通过SpringCloud Gateway实现API接口镜像请求(陪跑)网关功能