# 事务传播行为对比表解析

# 1. 什么是"当前有事务"

意思是:在调用这个方法的时候,已经有一个事务在运行了

@Transactional
public void 主方法() {
    // 这里已经开始了一个事务
    
    子方法();  // 调用子方法时,"当前有事务" ✅
}

public void 子方法() {
    // 当被主方法调用时,这里"当前有事务"
}
1
2
3
4
5
6
7
8
9
10

# 2. 什么是**"当前无事务"**

意思是:在调用这个方法的时候,没有事务在运行

public void 普通方法() {
    // 这里没有 @Transactional 注解
    
    子方法();  // 调用子方法时,"当前无事务" ✅
}
1
2
3
4
5

# 3. "典型场景"

这个就不用多说:

意思就是:这种传播行为最适合用在什么情况下。


# 重新解释的表格(用生活例子)

传播行为 当前有事务(有人排队) 当前无事务(没人排队) 你该怎么行动? 生活例子
REQUIRED (需要) 插队进去 (加入别人的队) 自己开个新队(新创建一个事务) 最常用,大家都这样做 食堂打饭:有队就排,没队就开新队
REQUIRES_NEW (必须新) 到旁边开个新队 (让别人先等着) 自己开个新队 独立的事,不受别人影响 买票时突然要上厕所:先离队去厕所,回来重新排队
NESTED (嵌套) 在队伍里做个标记 (可以单独退回标记点) 自己开个新队 大任务里的小任务 失败不影响整体 买套餐:主餐+饮料+甜点 饮料没了只退饮料钱
SUPPORTS (支持) 跟着排队 不排队了 直接办事 可排队可不排队的事 问路:如果别人在排队就问下,没排队就直接问
NOT_SUPPORTED (不支持) 不排队了 让队伍等着 不排队 长时间的事 别占着队伍 办护照要1小时:让其他人先办,你单独处理
NEVER (绝不允许) 大喊:不行! (抛异常) 不排队 绝不能排队的事 火灾逃生:绝不能排队!排队就危险!
MANDATORY (强制) 跟着排队 大喊:不行! (抛异常) 必须排队的事 银行取大额现金:必须排队办理,不能插队

# 场景1:REQUIRED(最常用)

@Service
public class 订单服务 {
    @Transactional  // 默认就是 REQUIRED
    public void 创建订单() {
        // 开始排队(新建事务)
        保存订单();
        扣库存();    // 也在同一个队伍里
        发短信();    // 也在同一个队伍里
        // 一起提交或一起回滚
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 场景2:REQUIRES_NEW(独立的事)

@Service  
public class 日志服务 {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void 记录日志() {
        // 不管别人在不在排队,我都要新开一个队
        // 我自己的事办完就提交,不受别人影响
    }
}

@Transactional
public void 下订单() {
    保存订单();  // 主队伍
    
    // 日志必须独立保存,就算订单失败也要记录
    日志服务.记录日志();  // 开新队伍
    
    // 如果这里出错,订单回滚,但日志已经保存
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 场景3:NESTED(套餐里的单品)

@Transactional
public void 批量导入员工() {
    for (员工 : 员工列表) {
        try {
            导入单个员工(员工);  // NESTED:套餐里的单品
        } catch (Exception e) {
            // 这个人导入失败,继续导入下一个
            // 只回滚这个人的操作
        }
    }
    // 所有人导入成功才一起提交
}

@Transactional(propagation = Propagation.NESTED)
public void 导入单个员工(员工) {
    // 如果失败,只回滚这个员工的操作
    // 不影响其他人
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 场景4:SUPPORTS(看情况)

@Transactional(propagation = Propagation.SUPPORTS)
public 报表 生成报表() {
    // 生成报表(查询操作)
    // 如果别人在事务中调用我,我就用他的事务
    // 如果别人不在事务中调用,我就不用事务
    
    // 适合:查询接口,可事务可非事务
}
1
2
3
4
5
6
7
8

# 场景5:NOT_SUPPORTED(别占着队伍)

@Transactional(propagation = Propagation.NOT_SUPPORTED)  
public void 导出Excel() {
    // 导出10万条数据到Excel(耗时5分钟)
    // 如果别人有事务,先挂起,让我先办
    // 办完了再恢复别人的事务
    
    // 适合:长时间操作,避免锁表太久
}
1
2
3
4
5
6
7
8

# 场景6:NEVER(严禁排队)

@Transactional(propagation = Propagation.NEVER)
public void 健康检查() {
    // 检查数据库连接是否正常
    // 绝对不能在有事务时调用!
    // 否则抛异常:IllegalTransactionStateException
    
    // 适合:监控、健康检查
}
1
2
3
4
5
6
7
8

# 场景7:MANDATORY(必须排队)

@Transactional(propagation = Propagation.MANDATORY)
public void 审计记录() {
    // 记录谁在什么时候做了什么
    // 必须和业务操作在同一个事务中!
    // 如果没事务就抛异常
    
    // 适合:审计日志,必须原子性
}
1
2
3
4
5
6
7
8

# 简单选择指南

问自己几个问题:

  1. 这个方法需要事务吗?
    • 需要 → 用 REQUIRED(默认)
    • 不需要 → 考虑 NOT_SUPPORTEDNEVER
    • 看情况SUPPORTS
  2. 这个方法失败时,要不要影响调用者?
    • 不要影响REQUIRES_NEW
    • 可以部分影响NESTED(如果数据库支持)
    • 必须一起REQUIRED
  3. 这个方法必须在事务中/外执行吗?
    • 必须在事务中MANDATORY
    • 必须在事务外NEVER

# 一句话总结

  • REQUIRED:随大流,有队就排,没队自开(90%的情况)
  • REQUIRES_NEW:我的事重要,开新队优先办
  • NESTED:大任务里的小步骤,失败不影响整体
  • SUPPORTS:可有可无,你们决定
  • NOT_SUPPORTED:别烦我,我要单独办
  • NEVER:谁让我排队我跟谁急!
  • MANDATORY:不排队就不给办!

现在明白了吗?主要是理解"当前有没有事务"就是指调用这个方法的时候,调用者自己是不是已经在事务中了

Last Updated: 12/4/2025, 10:23:47 AM