详解Spring中REQUIRED事务的回滚机制详解

 更新时间:2025年09月22日 10:49:00   作者:吟风于春  
在Spring的事务管理中,REQUIRED是最常用也是默认的事务传播属性,本文就来详细的介绍一下Spring中REQUIRED事务的回滚机制,感兴趣的可以了解一下

在 Spring 的事务管理中,REQUIRED 是最常用也是默认的事务传播属性。很多开发者在使用时会遇到一个常见的困惑:为什么内部方法抛出的异常即便被外层捕获了,事务还是会整体回滚? 本文将深入剖析 REQUIRED 下的事务回滚机制及其背后的原理。

1. REQUIRED 的定义

  • 默认传播属性
  • 如果当前存在事务:加入当前事务。
  • 如果没有事务:创建一个新事务。

这意味着调用链上的所有方法都运行在同一个物理事务里,彼此之间没有隔离。只要其中一个方法触发回滚条件,整个事务都会被撤销。

2. REQUIRED 下的回滚机制

2.1 异常触发回滚

Spring 默认回滚规则:

  • 运行时异常(RuntimeException)和错误(Error):触发回滚。
  • 受检异常(CheckedException):不会触发回滚,除非在 @Transactional(rollbackFor = Exception.class) 中显式指定。

2.2 回滚状态传播

假设调用链如下:

@Transactional(propagation = Propagation.REQUIRED)
public void outer() {
    try {
        inner();
    } catch (Exception e) {
        // 异常被捕获
    }
}

@Transactional(propagation = Propagation.REQUIRED)
public void inner() {
    throw new RuntimeException("内部错误");
}

执行过程:

  1. outer() 启动时创建事务。
  2. inner() 加入同一事务并抛出异常。
  3. Spring 的事务拦截器捕获异常 → 标记当前事务为 rollback-only
  4. 即便外层 outer() 捕获了异常,rollback-only 标记不会自动清除。
  5. 最终事务提交时,Spring 检查到 rollback-only → 调用 rollback() 而不是 commit()

因此,捕获异常并不能阻止事务回滚

3. 为什么捕获异常也会回滚?

原因在于 Spring 的事务是基于 事务状态标记 而不是你的 try-catch 来决定的:

  • 方法抛出异常 → TransactionInterceptor 判断是否需要回滚。
  • 如果符合规则 → status.setRollbackOnly()
  • 外层即便捕获异常,也只是业务层逻辑“消化”了异常,但事务状态已经不可提交。

最终由事务管理器在 commit() 阶段检查 rollback-only 标记,决定整体回滚。

4. 如何避免“误回滚”?

如果确实需要内部异常不影响外部事务,可以考虑以下方式:

4.1 修改回滚规则

@Transactional(noRollbackFor = RuntimeException.class)
public void inner() {
    throw new RuntimeException("不会触发回滚");
}

但这种方式风险极高,可能提交错误数据。

4.2 手动清理事务状态(不推荐)

catch (Exception e) {
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(false);
}

此方式非常危险,通常不建议。

4.3 使用其他传播属性(推荐)

  • REQUIRES_NEW:为内部方法开启新事务,失败只影响内部,不影响外部。
  • NESTED:使用保存点,内部失败可回滚到保存点,外部事务继续。

这两种方式才是更优雅的解决方案。

5. Spring 内部执行流程

核心逻辑在 TransactionAspectSupport.invokeWithinTransaction()

  1. 获取或创建事务。
  2. 执行目标方法。
  3. 捕获异常 → 判断是否需要回滚 → 设置 rollback-only。
  4. 方法结束 → 根据状态决定 commit() 还是 rollback()

6. 总结

  • REQUIRED 下,所有方法共享一个事务。
  • 任意方法异常触发 rollback-only → 整体回滚。
  • 捕获异常≠事务安全,Spring 根据事务状态决定提交还是回滚。
  • 如果需要更细粒度的控制,应使用 REQUIRES_NEWNESTED

一句话总结:在 Spring 的 REQUIRED 模式下,事务是一荣俱荣、一损俱损的整体,内部异常即便被捕获也会让整个事务回滚,真正想做到“局部回滚”需要换传播属性来实现。

到此这篇关于详解Spring中REQUIRED事务的回滚机制详解的文章就介绍到这了,更多相关Spring REQUIRED 事务回滚内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现象棋算法的示例代码

    Java实现象棋算法的示例代码

    象棋算法包括搜索算法、评估函数和剪枝算法,本文主要介绍了Java实现象棋算法的示例代码,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • 三道MySQL新手入门面试题,通往自由的道路

    三道MySQL新手入门面试题,通往自由的道路

    这篇文章主要为大家分享了最有价值的3道MySQL面试题,,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • SparkSQL使用IDEA快速入门DataFrame与DataSet的完美教程

    SparkSQL使用IDEA快速入门DataFrame与DataSet的完美教程

    本文给大家介绍使用idea开发Spark SQL 的详细过程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-08-08
  • java Date获取本月的开始时间与结束时间

    java Date获取本月的开始时间与结束时间

    这篇文章主要为大家介绍了java Date获取本月的开始时间与结束时间示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2023-05-05
  • 如何安装jdk及安装MyEclipse的图文教程

    如何安装jdk及安装MyEclipse的图文教程

    这篇文章主要介绍了如何安装jdk及安装MyEclipse的图文教程,需要的朋友可以参考下
    2018-03-03
  • SpringBoot+MyBatis-Plus实现数据库读写分离的代码示例

    SpringBoot+MyBatis-Plus实现数据库读写分离的代码示例

    在当今互联网应用中,数据库读写分离是提高系统性能和稳定性的重要手段之一,通过将读操作和写操作分别路由到不同的数据库节点,可以有效减轻数据库服务器的负担,本文将介绍如何利用SpringBoot和MyBatis-Plus框架实现数据库读写分离,需要的朋友可以参考下
    2023-11-11
  • Java原子操作CAS原理解析

    Java原子操作CAS原理解析

    这篇文章主要介绍了Java原子操作CAS原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • Java中常用数据类型的输入输出详解

    Java中常用数据类型的输入输出详解

    本文主要介绍了Java中几个常用的数据类型是如何输入和输出的,例如:Char型、int型、double型、数组、字符串等,对我们学习java有一定的帮助,感兴趣的小伙伴可以跟随小编一起学习学习
    2021-12-12
  • 在Java8与Java7中HashMap源码实现的对比

    在Java8与Java7中HashMap源码实现的对比

    这篇文章主要介绍了在Java8与Java7中HashMap源码实现的对比,内容包括HashMap 的原理简单介绍、结合源码在Java7中是如何解决hash冲突的以及优缺点,结合源码以及在Java8中如何解决hash冲突,balance tree相关源码介绍,需要的朋友可以参考借鉴。
    2017-01-01
  • 基于RocketMQ实现分布式事务的方法

    基于RocketMQ实现分布式事务的方法

    了保证系统数据的一致性,我们需要确保这些服务中的操作要么全部成功,要么全部失败,通过使用RocketMQ实现分布式事务,我们可以协调这些服务的操作,保证数据的一致性,这篇文章主要介绍了基于RocketMQ实现分布式事务,需要的朋友可以参考下
    2024-03-03

最新评论