编程式事务与声明式事务对比

结论先行声明式事务(@Transactional)基于 AOP 代理,无侵入、声明即用,但粒度只能到方法、且有自调用/非 public 等失效场景;编程式事务(TransactionTemplate 或 PlatformTransactionManager)在代码里显式圈定事务边界,粒度到语句块、自调用也生效、可动态决定回滚,但侵入业务代码。工程实践:90% 场景用声明式;单个方法内需要"分段事务、动态提交/回滚、循环中每项独立成败"时改用 TransactionTemplate 兜底。

一、对比表

维度声明式 @Transactional编程式 TransactionTemplate
实现AOP 代理拦截注解方法代码回调 execute(...)
侵入性无(一个注解)有(业务代码包裹)
粒度方法级语句块/任意范围
自调用失效不受代理影响,天然生效
动态回滚弱:只能靠抛异常强:可 setRollbackOnly、按条件提交
声明/配置注解 + 事务管理器注入 TransactionTemplate 即可
适用绝大多数 Service 方法批处理、MQ 消费、补偿、循环独立事务

二、代码示例

@Service
public class BatchService {
    private final TransactionTemplate tx;

    public void batchImport(List<Row> rows) {
        tx.executeWithoutResult(status -> {          // 整体一个事务
            for (Row r : rows) {
                save(r);
                if (r.isBad()) {
                    status.setRollbackOnly();        // 编程式:按条件标记回滚
                    return;
                }
            }
        });
        // 需要"每行独立事务"时:循环里分别 tx.execute(...),单行失败不影响其他行
    }
}

// 底层原语(更底层,一般不用)
// transactionManager.getTransaction(definition) → commit(ts) / rollback(ts)

常见追问 / 记忆点

  • 追问 1:TransactionTemplate 怎么配置?答:Boot 中注入 DataSourceTransactionManager 后,Spring 自动提供可用的 TransactionTemplate Bean,直接 @Autowired 即可。
  • 追问 2:声明式事务里想动态回滚怎么办?答:抛异常是首选;也可注入 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()(但可读性差,推荐抛自定义异常)。
  • 追问 3:两者能混用吗?答:能,声明式为主、编程式用于特殊边界;注意别在同一事务里叠出意外边界。
  • 记忆点:"声明式省事靠代理、粒度到方法;编程式兜底靠模板、粒度到代码块"。
笔记加载中…