Spring事务传播机制是怎样的一个?
摘要:Spring 事务传播机制是 Spring 事务中最核心也最易混淆的概念,它定义了一个带有事务的方法被另一个方法调用时,事务如何传递和生效(比如是否新建事务、是否加入已有事务、是否挂起事务等)。 核心前提:传播机制仅适用于Spring 管理
Spring 事务传播机制是 Spring 事务中最核心也最易混淆的概念,它定义了一个带有事务的方法被另一个方法调用时,事务如何传递和生效(比如是否新建事务、是否加入已有事务、是否挂起事务等)。
核心前提:传播机制仅适用于Spring 管理的 Bean 之间的方法调用(即通过代理对象调用),内部调用仍会导致事务失效(前文提到过)。
一、先理解核心概念
事务传播机制解决的核心问题:当方法 A(有事务)调用方法 B(有/无事务)时,B 的事务如何与 A 的事务交互?
当前事务:调用方方法已存在的事务上下文;
新事务:被调用方方法重新创建的独立事务;
无事务:被调用方方法不使用任何事务。
二、Spring 事务传播机制(7种核心类型)
Spring 在 TransactionDefinition 接口中定义了 7 种传播行为,按使用频率和场景分为三大类:
传播行为常量
中文名称
核心规则(关键!)
典型使用场景
REQUIRED(默认)
必须有事务
有则加入,无则新建
绝大多数业务场景(增删改)
SUPPORTS
支持事务
有则加入,无则无事务
查询类方法(可选事务)
MANDATORY
强制事务
有则加入,无则抛异常
必须在事务中执行的核心操作
REQUIRES_NEW
新建事务
无论有无,都新建事务,挂起当前事务
日志记录、异步通知(独立事务)
NOT_SUPPORTED
不支持事务
无论有无,都无事务,挂起当前事务
纯内存操作(无需事务)
NEVER
禁止事务
有事务则抛异常,无则无事务
绝对不允许在事务中执行的操作
NESTED
嵌套事务
有则嵌套(保存点),无则新建
主事务回滚不影响子事务(极少)
逐类详解(附代码示例)
1. 最常用:REQUIRED(默认)
核心逻辑:调用方有事务则加入,无则新建。
这是 Spring 事务的默认传播行为,也是日常开发中 90% 场景的选择。
@Service
public class OrderService {
@Autowired
private StockService stockService;
// 调用方:有事务
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder() {
// 1. 保存订单(当前事务)
saveOrder();
// 2. 调用库存服务(加入当前事务)
stockService.reduceStock();
// 3. 任意一步失败,整个事务回滚
}
}
@Service
public class StockService {
// 被调用方:REQUIRED(默认)
@Transactional
public void reduceStock() {
updateStock(); // 与创建订单在同一个事务中
}
}
效果:
如果 createOrder 先执行(有事务),reduceStock 会加入该事务,两者同成功/同失败;
如果直接调用 reduceStock(无事务),则新建事务执行。
2. 独立事务:REQUIRES_NEW
核心逻辑:无论调用方有无事务,都新建独立事务,原事务会被挂起,新事务执行完后恢复原事务。
适用于“即使主事务失败,子操作也必须提交”的场景(如记录操作日志)。
@Service
public class OrderService {
@Autowired
private LogService logService;
// 主事务
@Transactional
public void createOrder() {
saveOrder(); // 主事务操作
try {
// 调用日志服务(新建独立事务)
logService.recordLog("创建订单");
} catch (Exception e) {
// 日志记录失败不影响主事务
}
// 主事务失败回滚,日志事务已提交,不会回滚
}
}
@Service
public class LogService {
// 新建独立事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void recordLog(String content) {
insertLog(content); // 独立事务,与主事务无关
}
}
关键区别(REQUIRED vs REQUIRES_NEW):
场景
REQUIRED
REQUIRES_NEW
主事务回滚
子操作一起回滚
子操作已提交,不回滚
事务隔离
同一事务,共享锁/数据
独立事务,互不影响
3. 其他常用传播行为
SUPPORTS:有事务则加入,无则无事务。适合查询方法(如 getOrderById),如果外层有事务则用,没有也能执行;
MANDATORY:必须在事务中执行,否则抛 IllegalTransactionStateException。比如核心资金操作,强制要求外层有事务;
NOT_SUPPORTED:无论有无事务,都以无事务执行。比如纯缓存操作,不需要事务;
NEVER:绝对禁止事务,有则抛异常。比如某些敏感的非事务操作;
NESTED:嵌套事务(基于数据库保存点),主事务回滚到保存点时,子事务可独立回滚,极少使用(依赖数据库支持,如 MySQL InnoDB)。
三、经典场景对比(帮你快速选型)
业务场景
推荐传播行为
原因
订单创建 + 库存扣减
REQUIRED
同成功/同失败
订单创建 + 操作日志记录
REQUIRES_NEW
日志必须保存,不受主事务影响
仅查询订单详情
SUPPORTS
有事务则用,无则直接查
核心资金转账操作
MANDATORY
强制外层有事务,避免裸奔
纯内存计算/缓存更新
NOT_SUPPORTED
无需事务,提升性能
四、避坑要点
传播机制仅对代理调用生效:同一类内部调用(如 A.method1() 调用 A.method2()),传播机制失效,仍遵循“内部调用事务失效”规则;
REQUIRES_NEW 可能导致锁问题:新建事务会持有数据库锁,若主事务执行时间长,可能导致锁等待;
嵌套事务(NESTED)依赖数据库:仅支持有保存点(Savepoint)的数据库(如 MySQL/Oracle),且 Spring 对其支持有限,尽量用 REQUIRES_NEW 替代;
异常处理影响传播效果:如果子事务抛异常但被主事务捕获,需手动设置回滚(TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()),否则可能导致事务状态不一致。
五、实战验证方法
想验证传播机制是否生效?推荐 2 种方式:
日志调试:开启 Spring 事务日志,查看事务创建/挂起/提交日志:
<!-- logback 配置 -->
<logger name="org.springframework.transaction" level="DEBUG"/>
<logger name="org.springframework.jdbc.datasource.DataSourceTransactionManager" level="DEBUG"/>
数据库锁验证:在方法中加 Thread.sleep(10000),同时用 show processlist 查看数据库连接的事务状态。
总结
Spring 事务传播机制定义了多方法调用时事务的传递规则,核心是 7 种传播行为,其中 REQUIRED(默认)和 REQUIRES_NEW 是日常开发的核心;
REQUIRED 适用于“同成功/同失败”的关联操作,REQUIRES_NEW 适用于“独立执行、不受主事务影响”的操作;
传播机制仅对 Spring 代理调用生效,内部调用会失效,需通过注入代理对象解决。
