Spring Boot 七种事务传播行为只有 REQUIRES_NEW 和 NESTED 支持部分回滚的分析

发布于:2025-04-02 ⋅ 阅读:(22) ⋅ 点赞:(0)

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()

关键说明

  1. REQUIRES_NEW

    • 每个交易独立开启事务,失败时仅自身回滚,其他交易不受影响。
    • 适用场景:完全独立的交易,彼此无依赖。
  2. NESTED

    • 在父事务中创建保存点,失败时回滚到保存点,但父事务仍可提交。
    • 适用场景:交易间有弱关联,需局部回滚但整体提交成功。

注意:使用 NESTED 需确保数据库和驱动支持保存点(如MySQL/PostgreSQL)。


网站公告

今日签到

点亮在社区的每一天
去签到