news 2026/5/6 1:48:48

【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默认只在遇到RuntimeExceptionError时才会回滚,而非运行时异常不回滚

如果我们需要所有异常都回滚,需要来配置@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. 什么是事务传播机制

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

比如有两个方法AB都被@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;}}

💥nestedrequired的区别

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

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

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

Ⅲ. Spring 事务的失效问题

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

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

二、方法不是public💥

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

三、异常没抛出💥

  • 默认回滚规则: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/4/30 20:12:03

Gradio快速搭建Demo:三行代码创建DDColor交互界面

Gradio快速搭建Demo&#xff1a;三行代码创建DDColor交互界面 在老照片泛黄褪色的褶皱里&#xff0c;藏着几代人的记忆。如何让这些静止的黑白影像重新焕发生机&#xff1f;如今&#xff0c;AI图像着色技术已经能做到——不仅还原色彩&#xff0c;还能保留纹理与情感。但问题也…

作者头像 李华
网站建设 2026/5/2 23:28:17

从零开始训练Embedding模型:基于ms-swift的数据集配置详解

从零开始训练Embedding模型&#xff1a;基于ms-swift的数据集配置详解 在构建智能搜索、推荐系统或RAG&#xff08;检索增强生成&#xff09;应用时&#xff0c;一个高质量的文本向量表示能力往往是决定效果上限的关键。传统做法依赖预训练好的通用Embedding模型&#xff08;如…

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

安装包集中管理:企业内部模型分发系统的构建思路

企业内部模型分发系统的构建思路 在AI研发日益深入企业的今天&#xff0c;一个看似不起眼却影响深远的问题正悄然浮现&#xff1a;当团队成员每次启动新实验时&#xff0c;都要花上几小时甚至一整天去下载同一个大模型、配置环境、调试依赖——这不仅浪费资源&#xff0c;更拖慢…

作者头像 李华
网站建设 2026/4/20 5:25:24

网盘直链下载助手增强版:自动提取AI模型分享链接

网盘直链下载助手增强版&#xff1a;自动提取AI模型分享链接 在开源大模型爆发的今天&#xff0c;获取一个可用的预训练权重&#xff0c;往往不是打开 HuggingFace 点击“Download”那么简单。更多时候&#xff0c;你面对的是论坛里一段失效的百度网盘链接、加密压缩包、分卷文…

作者头像 李华
网站建设 2026/5/1 7:12:15

【C语言RISC-V跨平台适配终极指南】:掌握高效移植核心技术与实战技巧

第一章&#xff1a;C语言RISC-V跨平台适配概述随着RISC-V架构在嵌入式系统、高性能计算和教育领域的广泛应用&#xff0c;C语言作为其主要开发语言之一&#xff0c;面临越来越多的跨平台适配需求。由于RISC-V指令集具有模块化、可扩展的特点&#xff0c;不同厂商实现的硬件平台…

作者头像 李华
网站建设 2026/5/2 23:29:34

揭秘昇腾AI芯片底层优化:如何用C+汇编混合编程提升算子性能300%

第一章&#xff1a;揭秘昇腾AI芯片底层优化&#xff1a;如何用C汇编混合编程提升算子性能300%在昇腾AI芯片的高性能计算场景中&#xff0c;算子性能直接决定模型推理效率。通过C语言与汇编指令的深度混合编程&#xff0c;开发者可精准控制硬件资源&#xff0c;实现算法层与芯片…

作者头像 李华