★ Spring 事务传播行为详解

结论先行:传播行为解决"事务方法调用另一个事务方法时,事务如何扩散"的问题,共 7 种(TransactionDefinition/Propagation 枚举),默认 REQUIRED:外层有事务就加入、没有就新建。最高频的对比是 REQUIRES_NEW 与 NESTED:前者挂起外层开一个全新独立事务(内层回滚不影响外层,外层回滚也不牵连已提交的内层);后者用数据库 Savepoint 做嵌套(内层回滚只回退到保存点,整体仍是外层一个事务)。

一、7 种传播行为速查

传播行为外层有事务时外层无事务时典型场景
REQUIRED(默认)加入外层事务新建事务绝大多数业务方法
REQUIRES_NEW挂起外层,另开新事务新建事务审计日志、发消息(必须独立成败)
SUPPORTS加入非事务执行有则用之、无则不用
NOT_SUPPORTED挂起外层,非事务执行非事务执行长查询不占事务连接
MANDATORY加入抛 IllegalTransactionStateException强制调用方开事务
NEVER抛异常非事务执行禁止在事务内执行
NESTEDSavepoint 嵌套子事务新建事务批处理中单条失败可回退该项

二、代码示例

@Service
public class OrderService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void writeAuditLog(Order o) { }    // 独立事务:外层回滚不影响日志落库

    @Transactional(propagation = Propagation.NESTED)
    public void saveOneItem(Item i) { }       // Savepoint:本条失败只回退本条
}

三、高频追问要点

  • REQUIRES_NEW vs NESTED:前者是两个独立事务(各自提交/回滚,外层 catch 后仍可继续);后者同一事务内 Savepoint(内层回滚后外层可捕获继续,外层最终回滚则内层也滚);NESTED 依赖数据库 savepoint 支持(MySQL InnoDB 支持);
  • REQUIRED 的"rollback-only"陷阱:内外层同一个事务,内层回滚会把整个事务标记 rollback-only,即使外层 catch 了异常,外层提交时仍抛 UnexpectedRollbackException → 整体回滚;
  • 自调用时传播行为不生效(见 13/16:同类 this 调用不经过代理)。

常见追问 / 记忆点

  • 追问 1:REQUIRED 与 REQUIRES_NEW 最常用在什么对比场景?答:业务主流程用 REQUIRED;"日志必须写成功/失败不影响主流程"用 REQUIRES_NEW。
  • 追问 2:为什么 NESTED 不是真"子事务"?答:底层就是 Savepoint 回退点,没有独立的提交/回滚边界。
  • 记忆点:先记铁三角 REQUIRED / REQUIRES_NEW / NESTED,再补其余四个;"加入、新开、挂起、嵌套"各归其位。
笔记加载中…