Spring 事务传播机制详解
什么是事务传播机制
事务传播机制定义了当一个事务方法被另一个事务方法调用时,应该如何处理事务行为。Spring 框架提供了七种不同的事务传播行为,通过 @Transactional
注解的 propagation
属性进行设置。
七种事务传播机制及使用场景
1. REQUIRED(默认行为)
@Transactional(propagation = Propagation.REQUIRED)
特点:
- 如果当前存在事务,则加入该事务
- 如果当前没有事务,则创建一个新的事务
使用场景:
- 适用于大多数业务场景
- 希望多个操作在同一个事务中完成
- 例如:订单创建同时需要更新库存,两个操作要么都成功,要么都失败
2. REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
特点:
- 创建一个新的事务
- 如果当前存在事务,则挂起当前事务
使用场景:
- 当子业务流程需要独立事务时
- 子业务流程不应受到外部事务回滚的影响
- 例如:在处理订单过程中记录操作日志,即使订单处理失败,日志也应保存成功
3. SUPPORTS
@Transactional(propagation = Propagation.SUPPORTS)
特点:
- 如果当前存在事务,则加入该事务
- 如果当前没有事务,则以非事务方式执行
使用场景:
- 对事务要求不严格的查询操作
- 既可在事务环境运行也可在非事务环境运行的方法
- 例如:查询统计信息,不需要修改数据
4. NOT_SUPPORTED
@Transactional(propagation = Propagation.NOT_SUPPORTED)
特点:
- 以非事务方式执行操作
- 如果当前存在事务,则挂起当前事务
使用场景:
- 不希望在事务中执行的操作
- 需要提高性能的只读操作
- 例如:大数据量的统计查询,会长时间占用数据库连接
5. NEVER
@Transactional(propagation = Propagation.NEVER)
特点:
- 以非事务方式执行
- 如果当前存在事务,则抛出异常
使用场景:
- 确保方法不在事务中执行
- 作为一种安全检查机制
- 例如:某些工具类方法,明确不应该在事务上下文中调用
6. MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
特点:
- 如果当前存在事务,则加入该事务
- 如果当前没有事务,则抛出异常
使用场景:
- 确保方法必须在事务中执行
- 作为一种安全检查机制
- 例如:敏感的数据更新操作,必须在外部事务的控制下执行
7. NESTED
@Transactional(propagation = Propagation.NESTED)
特点:
- 如果当前存在事务,则在嵌套事务内执行
- 如果当前没有事务,则创建一个新事务
- 嵌套事务可以设置保存点,父事务回滚时子事务也回滚,子事务回滚不影响父事务
使用场景:
- 业务流程中有可分割的子步骤,可以单独回滚
- 例如:批量导入数据时,允许部分记录失败但不影响其他记录
常见组合使用场景
REQUIRED + REQUIRES_NEW
场景:主业务流程中包含日志记录
@Service
public class OrderService {
@Autowired
private LogService logService;
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder() {
// 处理订单业务
// ...
// 记录操作日志(即使订单失败也要保存日志)
logService.saveLog();
// 订单后续处理
// ...
}
}
@Service
public class LogService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog() {
// 日志记录逻辑
}
}
REQUIRED + NESTED
场景:批量导入数据,允许部分失败
@Service
public class ImportService {
@Autowired
private DataProcessor dataProcessor;
@Transactional(propagation = Propagation.REQUIRED)
public void batchImport(List<Data> dataList) {
for (Data data : dataList) {
try {
dataProcessor.process(data);
} catch (Exception e) {
// 记录错误,继续处理下一条
}
}
}
}
@Service
public class DataProcessor {
@Transactional(propagation = Propagation.NESTED)
public void process(Data data) {
// 处理单条数据
}
}
REQUIRED + NOT_SUPPORTED
场景:事务操作中需要执行耗时查询
@Service
public class ReportService {
@Autowired
private StatisticsService statisticsService;
@Transactional(propagation = Propagation.REQUIRED)
public void generateReport() {
// 事务操作
// ...
// 执行耗时统计查询
Map<String, Object> stats = statisticsService.calculateStatistics();
// 继续事务操作
// ...
}
}
@Service
public class StatisticsService {
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public Map<String, Object> calculateStatistics() {
// 执行复杂查询统计
return result;
}
}
注意事项
- 事务传播行为只有在事务方法之间相互调用时才会生效
- 基于代理的事务管理在同一个类中的方法调用不会触发事务传播行为
- 嵌套事务需要底层数据库和JDBC驱动支持保存点
REQUIRES_NEW
在高并发环境可能会创建大量事务,增加系统负担- 合理选择传播行为可以优化应用性能和数据一致性
正确理解和使用Spring事务传播机制,对实现复杂业务流程的事务管理至关重要。