Skip to content

事务传播行为

一、7 种传播行为

┌─────────────────────────────────────────────────────────────────┐
│                    7 种事务传播行为                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  REQUIRED(默认)                                                │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 有事务 → 加入                                              │   │
│  │ 无事务 → 创建新事务                                        │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  REQUIRES_NEW                                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 总是创建新事务                                            │   │
│  │ 挂起当前事务(如果有)                                     │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  SUPPORTS                                                       │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 有事务 → 加入                                              │   │
│  │ 无事务 → 非事务执行                                        │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  NOT_SUPPORTED                                                  │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 非事务执行                                                │   │
│  │ 挂起当前事务(如果有)                                     │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  MANDATORY                                                       │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 有事务 → 加入                                              │   │
│  │ 无事务 → 抛异常                                           │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  NEVER                                                          │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 非事务执行                                                │   │
│  │ 有事务 → 抛异常                                           │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  NESTED(嵌套事务)                                             │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 有事务 → 创建嵌套事务(savepoint)                        │   │
│  │ 无事务 → 创建新事务(等同 REQUIRED)                      │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

二、REQUIRED vs REQUIRES_NEW

┌─────────────────────────────────────────────────────────────────┐
│                  REQUIRED vs REQUIRES_NEW                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  REQUIRED(共享事务):                                         │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │          外层事务                                        │   │
│  │  ┌─────────────────────────────────────────────────┐   │   │
│  │  │              内层方法                             │   │   │
│  │  └─────────────────────────────────────────────────┘   │   │
│  │              同一事务,外层提交才都提交                    │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  REQUIRES_NEW(独立事务):                                      │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │          外层事务                                        │   │
│  └─────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              内层方法(新事务)                           │   │
│  └─────────────────────────────────────────────────────────┘   │
│              独立事务,各自提交/回滚                              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

三、NESTED 嵌套事务

┌─────────────────────────────────────────────────────────────────┐
│                      NESTED 嵌套事务                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  使用数据库 Savepoint 机制                                       │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    外层事务                               │   │
│  │                                                         │   │
│  │         savepoint: sp1                                   │   │
│  │                   │                                      │   │
│  │  ┌─────────────────────────────────────────────────┐   │   │
│  │  │              嵌套事务                           │   │   │
│  │  │         嵌套失败 → rollback to sp1              │   │   │
│  │  │         外层继续                                │   │   │
│  │  └─────────────────────────────────────────────────┘   │   │
│  │                   │                                      │   │
│  │            外层提交                                      │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  嵌套失败只回滚到 savepoint,不影响外层                         │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

四、常见场景

日志记录

java
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void log(String operation, String content) {
    // 独立事务,即使业务失败日志也应记录
    logRepository.save(operation, content);
}

发送消息

java
@Transactional
public void createOrder(Order order) {
    orderRepository.save(order);
    
    // 发送消息,即使失败也不影响订单创建
    try {
        messageService.sendOrderCreated(order);
    } catch (Exception e) {
        log.error("发送消息失败", e);
    }
}

财务转账

java
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
    // 扣款
    accountRepository.reduceBalance(fromId, amount);
    
    // 存款(嵌套事务,失败不影响扣款)
    try {
        accountService.deposit(toId, amount);
    } catch (Exception e) {
        // 记录异常,不回滚主事务
        log.error("存款失败", e);
    }
}

@Transactional(propagation = Propagation.NESTED)
public void deposit(Long accountId, BigDecimal amount) {
    accountRepository.addBalance(accountId, amount);
}

五、事务失效场景

1. 非 public 方法

java
@Service
public class UserService {
    
    @Transactional  // 不生效!Spring AOP 只支持 public 方法
    private void save(User user) {
        // ...
    }
}

2. 内部调用

java
@Service
public class UserService {
    
    @Transactional
    public void methodA() {
        methodB();  // this.methodB(),不经过代理
    }
    
    @Transactional  // 不生效!
    public void methodB() {
        // ...
    }
}

3. 异常被吞

java
@Transactional
public void save(User user) {
    try {
        // 业务
    } catch (Exception e) {
        // 异常被吞掉,事务不回滚
    }
}

4. 传播行为错误

java
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void save(User user) {
    // NOT_SUPPORTED 会挂起事务,变成非事务执行
}

六、面试高频问题

Q1: REQUIRED 和 REQUIRES_NEW 区别?

  • REQUIRED:共享当前事务,没有则创建
  • REQUIRES_NEW:总是创建新事务,挂起旧事务

Q2: NESTED 和 REQUIRED 区别?

  • REQUIRED:共享事务
  • NESTED:使用 savepoint,嵌套部分失败只回滚到 savepoint

Q3: 什么情况下事务会失效?

  1. 非 public 方法
  2. 内部调用(this.xxx())
  3. 异常被 catch 吞掉
  4. 传播行为设置为 NOT_SUPPORTED

Q4: 默认对哪些异常回滚?

RuntimeException 和 Error,不对 Checked Exception 回滚(除非配置 rollbackFor)

七、Spring 全家桶总结

Spring Framework
├── IoC/DI                    ✅
├── AOP                       ✅
├── Bean 生命周期             ✅
├── 三级缓存/循环依赖          ✅
└── 动态代理                  ✅

Spring Boot
├── 自动配置                  ✅
├── starter                   ✅
├── 配置文件                  ✅
└── 条件装配                  ✅

Spring MVC
├── 请求处理流程               ✅
├── 参数绑定                   ✅
├── 视图解析                   ✅
├── 拦截器/过滤器             ✅
└── 异常处理                   ✅

Spring Data
├── JDBC                      ✅
├── JPA                       ✅
├── Redis                     ✅
└── 事务管理                  ✅

Spring Security
├── 认证/授权                  ✅
├── JWT                       ✅
├── RBAC                      ✅
└── OAuth2                    ✅

Spring Cloud
├── Nacos                     ✅
├── Gateway                   ✅
├── Feign                     ✅
├── Sentinel                  ✅
└── Config                    ✅

Spring 系列文档全部完成! 🎉

基于 MIT 许可发布