news 2026/4/3 5:30:24

【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/3/30 6:59:18

【SpringBoot】validation参数校验 JWT鉴权实现 加密/加盐

文章目录参数校验&#xff1a;jakarta.validation常见注解使用实例如何触发验证&#xff1f;JWT1. 传统登录方式的问题2. JWT令牌技术解决方案令牌技术优点JWT介绍JWT组成3. 实现JWT登录认证3.1 添加JWT依赖3.2 创建JWT工具类3.3 创建配置类3.4 前端实现的细节4. Auth0 提供的 …

作者头像 李华
网站建设 2026/3/30 19:08:04

谷歌镜像还能做什么?搜索AI论文与技术文档的高效方式

谷歌镜像还能做什么&#xff1f;搜索AI论文与技术文档的高效方式 在今天这个大模型“井喷”的时代&#xff0c;打开Hugging Face或ModelScope&#xff0c;动辄上千个开源模型扑面而来&#xff1a;Llama3、Qwen、ChatGLM、InternVL……名字一个比一个响亮&#xff0c;参数规模一…

作者头像 李华
网站建设 2026/4/3 4:44:37

基于蜂鸣器电路的工业声光报警装置构建方法

蜂鸣器不止“嘀”一声&#xff1a;如何打造工业级声光报警系统你有没有遇到过这样的场景&#xff1f;在嘈杂的车间里&#xff0c;设备突然故障&#xff0c;控制柜上的指示灯闪了——可没人注意到。操作员正戴着耳塞调试机器&#xff0c;远处巡检的人视线被管道遮挡……等发现异…

作者头像 李华
网站建设 2026/4/2 8:26:23

【C与Python混合编程核心技巧】:掌握热点函数调用的5大高性能方案

第一章&#xff1a;C与Python混合编程概述在现代软件开发中&#xff0c;性能与开发效率的平衡至关重要。C语言以其高效的执行速度和底层系统控制能力著称&#xff0c;而Python则以简洁语法和快速开发见长。将两者结合进行混合编程&#xff0c;可以在关键性能模块使用C语言实现&…

作者头像 李华
网站建设 2026/4/2 3:14:54

C语言WASM性能调优实战(从编译到运行时的全面提速方案)

第一章&#xff1a;C语言WASM性能调优的背景与意义随着WebAssembly&#xff08;简称WASM&#xff09;在现代浏览器中的广泛支持&#xff0c;越来越多高性能计算场景开始将其作为核心执行载体。C语言因其接近硬件的执行效率和对内存的精细控制&#xff0c;成为编译至WASM的首选语…

作者头像 李华