news 2026/9/30 6:10:57

【SpringBoot】Spring事务 @Transactional详解 Spring事务失效问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【SpringBoot】Spring事务 @Transactional详解 Spring事务失效问题

文章目录

  • Ⅰ. Spring中事务的实现
    • 一、编程式事务(了解)
    • 二、声明式事务:`@Transactional`
      • @Transactional 的作用
  • Ⅱ. @Transactional 详解
    • 一、异常回滚属性 `rollbackFor`
    • 二、Spring事务隔离级别 `Isolation`
    • 三、Spring事务传播机制 `Propagation`
      • 1. 什么是事务传播机制
      • 2. 事务的传播机制有哪些
      • 💥`nested` 和 `required` 的区别
  • Ⅲ. Spring 事务的失效问题
    • 一、调用方式不对(自调用)💥
    • 二、方法不是 `public`💥
    • 三、异常没抛出💥
    • 四、数据库引擎不支持事务
    • 五、多线程调用💥
    • 六、配置问题
    • 七、手动设置了传播属性
    • ✅ 快速排查清单

Ⅰ. Spring中事务的实现

Spring中的事务操作分为两类:

  1. 编程式事务(手动实现事务)
  2. 声明式事务(利用注解自动开启事务)

一、编程式事务(了解)

Spring 手动操作事务和 MySQL 操作事务类似,有三个重要操作步骤:

  1. 开启事务(获取事务)
  2. 提交事务
  3. 回滚事务

SpringBoot 内置了两个对象:

  1. DataSourceTransactionManager:事务管理器,用来获取事务(开启事务),提交或回滚事务的
  2. TransactionDefinition:事务的属性,在获取事务的时候需要将TransactionDefinition传递进去从而获得一个事务TransactionStatus

代码实现:

importcom.example.demo.service.UserService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.jdbc.datasource.DataSourceTransactionManager;importorg.springframework.transaction.TransactionDefinition;importorg.springframework.transaction.TransactionStatus;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/user")@RestControllerpublicclassUserController{// 注入事务管理器@AutowiredprivateDataSourceTransactionManagerdataSourceTransactionManager;// 注入事务属性@AutowiredprivateTransactionDefinitiontransactionDefinition;@AutowiredprivateUserServiceuserService;@RequestMapping("/registry")publicStringregistry(Stringname,Stringpassword){// 开启事务TransactionStatustransactionStatus=dataSourceTransactionManager.getTransaction(transactionDefinition);// 用户注册userService.registryUser(name,password);// 提交事务dataSourceTransactionManager.commit(transactionStatus);// 回滚事务//dataSourceTransactionManager.rollback(transactionStatus);return"注册成功";}}

二、声明式事务:@Transactional

  1. 添加依赖

    <dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId></dependency>
  2. 在需要事务的方法上添加@Transactional注解就可以实现了。无需手动开启事务和提交事务,进入方法时自动开启事务,方法执行完会自动提交事务,如果中途发生了没有处理的异常会自动回滚事务。

    @RequestMapping("/trans")@RestControllerpublicclassTransactionalController{@AutowiredprivateUserServiceuserService;@Transactional@RequestMapping("/registry")publicStringregistry(Stringname,Stringpassword){// 用户注册userService.registryUser(name,password);return"注册成功";}}

@Transactional 的作用

  • 修饰方法时:只有修饰public方法时才生效(修饰其他方法时不会报错,也不生效)[推荐]
  • 修饰类时:对@Transactional修饰的类中所有的public方法都生效。

💥注意事项:

  • 如果在方法执行过程中,出现异常,且异常未被捕获,就进行事务回滚操作。
  • 如果异常被程序捕获,方法就被认为是成功执行,依然会提交事务。

下面对异常进行捕获:

@Transactional@RequestMapping("/registry")publicStringregistry(Stringname,Stringpassword){userService.registryUser(name,password);// 模拟用户注册功能log.info("用户数据插入成功");// 对异常进行捕获try{// 强制程序抛出异常inta=10/0;}catch(Exceptione){e.printStackTrace();}return"注册成功";}

运行程序,发现虽然程序出错了,但是由于异常被捕获了,所以事务依然得到了提交。

如果需要事务进行回滚,有以下两种方式:

  1. 重新抛出异常

    @Transactional@RequestMapping("/registry")publicStringregistry(Stringname,Stringpassword){userService.registryUser(name,password);log.info("用户数据插入成功");// 对异常进行捕获try{inta=10/0;}catch(Exceptione){// 将异常重新抛出去throwe;}return"注册成功";}
  2. 手动回滚事务:使用TransactionAspectSupport.currentTransactionStatus()得到当前的事务,并使用setRollbackOnly设置回滚。

    @Transactional@RequestMapping("/registry")publicStringregistry(Stringname,Stringpassword){userService.registryUser(name,password);log.info("用户数据插入成功");// 对异常进行捕获try{inta=10/0;}catch(Exceptione){// 手动回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return"注册成功";}

Ⅱ. @Transactional 详解

这里主要介绍注解中三个常见属性:

  1. rollbackFor:异常回滚属性。指定能够触发事务回滚的异常类型。可以指定多个异常类型
  2. Isolation:事务的隔离级别。默认值为Isolation.DEFAULT
  3. Propagation:事务的传播机制。默认值为Propagation.REQUIRED

一、异常回滚属性rollbackFor

@Transactional默认只在遇到RuntimeException和Error时才会回滚,而非运行时异常不回滚。

如果我们需要所有异常都回滚,需要来配置@Transactional注解当中的rollbackFor属性,通过这个属性指定出现何种异常类型时事务进行回滚。

// Controller 层@RequestMapping("/r2")publicStringr2(Stringname,Stringpassword)throwsIOException{userService.registryUserWithTx(name,password);return"r2";}// Service 层@Transactional(rollbackFor=Exception.class)publicvoidregistryUserWithTx(Stringname,Stringpassword)throwsIOException{userRepository.save(newUser(name,password));log.info("用户数据插入成功");if(true){thrownewIOException();// 模拟异常}}

发现虽然程序抛出了异常,但是事务依然进行了回滚!

二、Spring事务隔离级别Isolation

隔离级别含义
Isolation.DEFAULT以连接的数据库的事务隔离级别为主
Isolation.READ_UNCOMMITTED读未提交
Isolation.READ_COMMITTED读已提交
Isolation.REPEATABLE_READ可重复读
Isolation.SERIALIZABLE串行化

它的实现如下所示:

publicenumIsolation{DEFAULT(-1),READ_UNCOMMITTED(1),READ_COMMITTED(2),REPEATABLE_READ(4),SERIALIZABLE(8);privatefinalintvalue;privateIsolation(intvalue){this.value=value;}publicintvalue(){returnthis.value;}}

Spring 中事务隔离级别可以通过@Transactional中的isolation属性进行设置:

@Transactional(isolation=Isolation.READ_COMMITTED)@RequestMapping("/r3")publicStringr3(Stringname,Stringpassword)throwsIOException{//... 代码省略return"r3";}

三、Spring事务传播机制Propagation

1. 什么是事务传播机制

事务传播机制就是:多个事务方法存在调用关系时,事务是如何在这些方法间进行传播的。

比如有两个方法A,B都被@Transactional修饰,A方法调用B方法

A方法运行时,会开启一个事务。当A调用B时,B方法本身也有事务,此时B方法运行时,是加入A的事务呢,还是创建一个新的事务呢?

这就涉及到了事务的传播机制。

  • 事务隔离级别解决的是多个事务同时调用一个数据库的问题。

  • 事务传播机制解决的是一个事务在多个方法之间传递的问题。

2. 事务的传播机制有哪些

@Transactional注解支持事务传播机制的设置,通过propagation属性来指定传播行为。

传播机制作用
Propagation.REQUIRED默认的事务传播级别。如果当前存在事务,则加入该事务。如果当前没有事务,则创建一个新的事务。
Propagation.SUPPORTS如果当前存在事务,则加入该事务。如果当前没有事务,则以非事务的方式继续运行。
Propagation.MANDATORY如果当前存在事务,则加入该事务。如果当前没有事务,则抛出异常。
Propagation.REQUIRES_NEW如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干扰。
Propagation.NOT_SUPPORTED以非事务方式运行,如果当前存在事务,则把当前事务挂起,不使用它。
Propagation.NEVER以非事务方式运行,如果当前存在事务,则抛出异常。
Propagation.NESTED如果当前存在事务,则创建一个事务作为当前事务的子事务来运行。如果当前没有事务,则创建一个新的事务。

实现类如下所示:

publicenumPropagation{REQUIRED(0),SUPPORTS(1),MANDATORY(2),REQUIRES_NEW(3),NOT_SUPPORTED(4),NEVER(5),NESTED(6);privatefinalintvalue;privatePropagation(intvalue){this.value=value;}publicintvalue(){returnthis.value;}}

💥nested和required的区别

  • 整个事务如果全部执行成功,二者的结果是一样的。
  • 如果事务部分执行成功
    • REQUIRED加入事务会导致整个事务全部回滚。
    • NESTED嵌套事务可以实现局部回滚,不会影响上一个方法中执行的结果。

嵌套事务之所以能够实现部分事务的回滚,是因为事务中有一个保存点(savepoint)的概念,嵌套事务进入之后相当于新建了一个保存点,而滚回时只回滚到当前保存点。

REQUIRED是加入到当前事务中,并没有创建事务的保存点,因此出现了回滚就是整个事务回滚,这就是嵌套事务和加入事务的区别!

Ⅲ. Spring 事务的失效问题

一、调用方式不对(自调用)💥

  • 场景:在同一个类里,一个方法调用另一个加了@Transactional的方法。
  • 原因:Spring 事务是通过代理实现的,内部方法调用不会走代理,事务不会生效。
  • 解决:把需要事务的方法放到另一个类里,或通过 AopContext 获取代理调用。
    • 具体可以参考《黑马点评》中的优惠券一人一单问题。

二、方法不是public💥

  • Spring 默认只对public方法生效。
  • 如果@Transactional标注在private、protected或default方法上,事务不会生效。

三、异常没抛出💥

  • 默认回滚规则:Spring 只会对运行时异常(RuntimeException 或其子类)回滚。

  • 如果你捕获异常后没抛出,事务不会回滚。

  • 如果抛的是受检异常(如IOException),默认也不会回滚。

  • 解决:

    • 重新抛出运行时异常。

    • 或在注解里指定rollbackFor:

    • @Transactional(rollbackFor=Exception.class)

四、数据库引擎不支持事务

  • MySQL 如果表引擎是 MyISAM,不支持事务,事务自然无效。
  • 必须用 InnoDB 才能支持。

五、多线程调用💥

  • 如果事务方法里开了新线程,线程里的操作不受当前事务控制。
  • 解决:避免在事务方法里直接用多线程,或者手动管理事务。

六、配置问题

  • @EnableTransactionManagement没配置。
  • 事务管理器没有正确注入。

七、手动设置了传播属性

  • 如果事务传播属性设置不当(如PROPAGATION_NEVER),也会导致失效。

✅ 快速排查清单

  1. 方法必须是public
  2. 确保是代理调用(不是同类内调用)
  3. 确保异常能抛出,没被吞掉
  4. 数据库表必须支持事务
  5. 确认 Spring 的事务配置启用

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 9:07:55

LUT调色包应用场景匹配:根据画面内容推荐最佳配色

LUT调色包应用场景匹配&#xff1a;根据画面内容推荐最佳配色 在影视后期、广告制作和数字内容创作中&#xff0c;调色从来不只是“让画面更好看”这么简单。它承载着情绪表达、风格定义甚至品牌识别的重任。然而&#xff0c;一个资深调色师花十分钟试错五个LUT&#xff08;查…

作者头像 李华
网站建设 2026/9/29 9:07:42

/root/yichuidingyin.sh脚本详解:自动化部署的核心逻辑

/root/yichuidingyin.sh 脚本详解&#xff1a;自动化部署的核心逻辑 在大模型技术飞速演进的今天&#xff0c;一个70亿参数的语言模型已经不再稀奇——真正让人头疼的是&#xff0c;如何在有限时间内把这样一个庞然大物从下载、训练到上线服务完整跑通。传统流程中&#xff0c;…

作者头像 李华
网站建设 2026/9/29 9:07:44

PyCharm插件市场新增AI助手:代码补全与错误修复一体化

PyCharm插件市场新增AI助手&#xff1a;代码补全与错误修复一体化 在今天的Python开发环境中&#xff0c;一个新趋势正悄然改变开发者的工作流——越来越多的AI编程助手开始出现在PyCharm的插件市场中。这些插件不再只是简单的语法提示工具&#xff0c;而是能够理解上下文、自动…

作者头像 李华
网站建设 2026/9/29 9:07:46

CDN加速服务接入:全球多地节点确保图片上传下载流畅

CDN加速服务接入&#xff1a;全球多地节点确保图片上传下载流畅 在数字内容呈指数级增长的今天&#xff0c;一张泛黄的老照片可能承载着几代人的记忆。无论是家庭相册中的黑白影像&#xff0c;还是城市建筑的历史档案&#xff0c;如何让这些珍贵的画面“活”起来&#xff0c;成…

作者头像 李华
网站建设 2026/9/29 8:51:37

C17标准更新后如何确保代码兼容?:3大关键测试策略一文讲透

第一章&#xff1a;C17标准的核心变更与兼容性挑战C17&#xff08;也称为C18&#xff09;作为ISO/IEC 9899:2018标准的通用名称&#xff0c;是C语言继C11之后的修订版本&#xff0c;主要聚焦于错误修复和缺陷澄清&#xff0c;而非引入大规模新特性。尽管其变更幅度较小&#xf…

作者头像 李华
网站建设 2026/9/30 4:23:38

高校科研团队适用:教育场景下的免费算力申请通道

高校科研团队适用&#xff1a;教育场景下的免费算力申请通道 在人工智能研究的浪潮中&#xff0c;越来越多高校团队希望投身大模型与多模态系统的探索。然而现实却常常令人望而却步——动辄数十GB显存的训练需求、复杂的分布式配置、漫长的模型下载过程&#xff0c;再加上高昂…

作者头像 李华