Spring事务传播行为七种类型

wen java案例 2

本文目录导读:

Spring事务传播行为七种类型

  1. 核心分类(以是否支持当前事务为界)
  2. 核心分类(以创建新事务为主)
  3. NESTED(嵌套事务)— 特殊且强大
  4. 核心对比表
  5. 实战常见面试点

Spring 的事务传播行为(Transaction Propagation)定义了当一个事务方法被另一个事务方法调用时,事务的边界应该如何扩散

通俗地说,就是解决方法嵌套调用时,是共用同一个事务,还是各自独立事务,或者创建新事务的问题。

Spring 定义了 7种 传播行为(基于 Propagation 枚举),下面逐一说明。


核心分类(以是否支持当前事务为界)

REQUIRED(必须的)— 最常用,默认值

  • 行为:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • 场景:绝大多数业务方法适用。A.save() 调用 B.save(),两者应在同一个事务中,要么都成功,要么都回滚。
  • 示例
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodA() {
        // ...
        methodB(); // methodB 会使用 methodA 的同一事务
    }

SUPPORTS(支持的)

  • 行为:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
  • 场景:某些查询方法,有事务更好(能读已提交等),没有事务也能跑。
  • 注意:非事务环境下执行时,可能导致脏读、不可重复读等问题。

MANDATORY(强制的)

  • 行为:必须在现有事务中执行,如果当前没有事务,则直接抛出异常
  • 场景:该方法不允许被没有事务的调用者执行,确保调用方必须开启事务。
  • 示例@Transactional(propagation = Propagation.MANDATORY)

核心分类(以创建新事务为主)

REQUIRES_NEW(总是新事务)— 常用

  • 行为无论当前是否存在事务,都挂起当前事务,创建一个全新的独立事务
  • 关键点
    • 新事务与外部事务互不影响,外层回滚,内层已提交则不受影响(需捕获异常);内层回滚,外层可以继续提交(除非捕获到内层异常)。
  • 场景
    • 日志记录:业务回滚了,但操作日志必须写入(不能因为业务失败而丢失日志)。
    • 发消息:业务失败了,但MQ消息已发送,不希望消息也被回滚。
  • 示例
    @Transactional
    public void outer() {
        inner(); // 如果这里抛出异常,但 inner 已提交,则 outer 回滚不影响 inner
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void inner() { ... }

NOT_SUPPORTED(不支持事务)

  • 行为:以非事务方式执行,如果当前存在事务,则挂起当前事务
  • 场景:包含一些不需要事务、且可能耗时较长的操作(如批量大文件处理),避免长时间占用数据库连接。

NEVER(绝不)

  • 行为:以非事务方式执行,如果当前存在事务,则直接抛出异常
  • 场景:强制要求调用方不能有事务,例如某些必须在无事务环境下执行的清空数据操作(避免自动清空被回滚)。

NESTED(嵌套事务)— 特殊且强大

  • 行为:如果当前存在事务,则在嵌套事务内执行(利用数据库的 Savepoint 保存点机制);如果当前没有事务,则行为同 REQUIRED
  • 关键点
    • 不是新事务:内层回滚,可以回滚到嵌套的保存点,不影响外层
    • 外层回滚:内层也一起回滚。
    • 前提:数据库必须支持保存点(主流数据库如 MySQL、Oracle 都支持)。
  • REQUIRES_NEW 的区别
    • REQUIRES_NEW:内层是独立事务,外层不能看到内层的未提交状态,且内层提交后不受外层影响。
    • NESTED:内层是外层的一部分,外层能看到内层的未提交状态,内层回滚仅回滚到保存点,不结束外层事务。
  • 场景
    • 批量操作,部分失败允许跳过:比如批量导入100条数据,第50条失败。NESTED 允许回滚到第50条之前,继续执行第51条;REQUIRES_NEW 则第50条失败需要单独处理,且第50条之前的已提交(更复杂)。

核心对比表

传播行为 是否有当前事务 行为 典型场景
REQUIRED 加入 默认选择,方法嵌套共享事务
新建
SUPPORTS 加入 查询方法,有事务更好,无事务也行
非事务运行
MANDATORY 加入 强制调用方必须有事务
抛出异常
REQUIRES_NEW 挂起当前,新建独立事务 日志、审计、消息发送
新建
NOT_SUPPORTED 挂起当前,非事务运行 耗时非事务操作
非事务运行
NEVER 抛出异常 强制无事务环境
非事务运行
NESTED 嵌套事务(保存点) 批量处理,部分异常可跳过
新建(同REQUIRED)

实战常见面试点

  1. REQUIRED vs REQUIRES_NEW:前者是“同生共死”;后者是“各管各的”。
  2. NESTED vs REQUIRES_NEW:前者外层回滚内层必回滚;后者外层回滚不影响内层(若内层已提交)。
  3. 事务传播只在方法调用时生效:必须在代理对象(AOP代理,如Spring管理的Bean)之间调用才生效。同类内部方法调用(this.xxx())不会触发事务传播(因为不走代理)。
  4. 默认值@Transactional 不加参数时,默认是 REQUIRED

抱歉,评论功能暂时关闭!