开发者

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

目录
  • 1. REQUIRED 的定义
  • 2. REQUIRED 下的回滚机制
    • 2.1 异常触发回滚
    • 2.2 回滚状态传播
  • 3.js 为什么捕获异常也会回滚?
    • 4. 如何避免“误回滚”?
      • 4.1 修改回滚规则
      • 4.2 手动清理事务状态(不推荐)
      • 4.3 使用其他传播属性(推荐)
    • 5. Spring 内部执行流程
      • 6. 总结

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

        1. REQUIRED 的定义

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

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

        2. REQUIRED 下的回滚机制

        2.1 异常触发回滚

        Spring 默认回滚规则:

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

        2.2 回滚状态传播

        假设调用链如下:

        @Transactional(propagation = Propagation.REQUIRED)
        public void ouwww.devze.comter() {
            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 使用其他传播js属性(推荐)

        • 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 事务回滚内容请搜索编程客栈(jswww.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜