Spring Boot 七种事务传播行为支持部分回滚的分析
支持部分回滚的传播行为
REQUIRES_NEW
:始终开启新事务,独立于外部事务,失败时仅自身回滚。NESTED
:在当前事务中创建保存点(Savepoint),可局部回滚到保存点,不影响外部事务整体提交。
代码示例:使用 REQUIRES_NEW
实现部分回滚
1. 交易服务层(独立事务)
@Service
public class TransactionService {
@Autowired
private TradeRepository tradeRepository;
// 使用 REQUIRES_NEW,每个交易独立事务
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void processTrade(Trade trade) {
try {
// 模拟业务逻辑(如保存交易)
tradeRepository.save(trade);
if (trade.getId() == 3) { // 模拟交易3失败
throw new RuntimeException("Transaction 3 failed");
}
} catch (Exception e) {
// 本地异常处理,但事务仍会回滚
throw e;
}
}
}
2. 批量任务协调者
@Service
public class BatchProcessor {
@Autowired
private TransactionService transactionService;
// 批量任务不开启事务(NOT_SUPPORTED)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void executeBatch(List<Trade> trades) {
for (Trade trade : trades) {
try {
transactionService.processTrade(trade);
} catch (Exception e) {
// 记录错误但继续处理其他交易
System.out.println("Trade " + trade.getId() + " failed!");
}
}
}
}
3. 测试用例
@SpringBootTest
public class BatchTest {
@Autowired
private BatchProcessor batchProcessor;
@Autowired
private TradeRepository tradeRepository;
@Test
public void testBatchProcessing() {
List<Trade> trades = Arrays.asList(
new Trade(1, "Success1"),
new Trade(2, "Success2"),
new Trade(3, "Failed") // 交易3会失败
);
batchProcessor.executeBatch(trades);
// 验证:交易1和2已提交,交易3未提交
assertEquals(2, tradeRepository.count());
}
}
代码示例:使用 NESTED
实现部分回滚
1. 交易服务层(嵌套事务)
@Service
public class TransactionService {
@Autowired
private TradeRepository tradeRepository;
// 使用 NESTED,在外部事务中创建保存点
@Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class)
public void processTradeWithNested(Trade trade) {
try {
tradeRepository.save(trade);
if (trade.getId() == 3) {
throw new RuntimeException("Transaction 3 failed");
}
} catch (Exception e) {
throw e; // 回滚到保存点,但外部事务可继续提交其他交易
}
}
}
2. 批量任务协调者(需开启外部事务)
@Service
public class BatchProcessor {
@Autowired
private TransactionService transactionService;
// 开启外部事务(REQUIRED)
@Transactional(propagation = Propagation.REQUIRED)
public void executeBatchWithNested(List<Trade> trades) {
for (Trade trade : trades) {
try {
transactionService.processTradeWithNested(trade);
} catch (Exception e) {
System.out.println("Trade " + trade.getId() + " failed!");
// 继续处理其他交易
}
}
// 手动提交外部事务(可选,但通常由Spring自动管理)
}
}
传播行为对比表格
传播行为 | 是否支持部分回滚 | 适用场景 | 代码示例方法 |
---|---|---|---|
REQUIRED |
❌ 不支持 | 继承父事务,失败时所有操作回滚 | - |
REQUIRES_NEW |
✅ 支持 | 独立事务,失败不影响其他交易 | processTrade() |
SUPPORTS |
❌ 不支持 | 无事务或依赖父事务 | - |
NOT_SUPPORTED |
❌ 不支持 | 挂起父事务,无事务执行 | - |
MANDATORY |
❌ 不支持 | 必须存在父事务 | - |
NEVER |
❌ 不支持 | 禁止存在父事务 | - |
NESTED |
✅ 支持 | 在父事务中创建保存点,局部回滚 | processTradeWithNested() |
关键说明
REQUIRES_NEW
- 每个交易独立开启事务,失败时仅自身回滚,其他交易不受影响。
- 适用场景:完全独立的交易,彼此无依赖。
NESTED
- 在父事务中创建保存点,失败时回滚到保存点,但父事务仍可提交。
- 适用场景:交易间有弱关联,需局部回滚但整体提交成功。
注意:使用 NESTED
需确保数据库和驱动支持保存点(如MySQL/PostgreSQL)。