编程式事务控制通过代码显式管理事务,适用于动态判断、多分支、嵌套边界不固定等复杂场景;核心为platformtransactionmanager与transactiontemplate,后者推荐使用,自动处理提交回滚,需关注业务逻辑与异常控制。

编程式事务控制是在代码中显式调用事务开始、提交或回滚的方法,适合需要动态判断、多条件分支、嵌套事务边界不固定等复杂场景。它不依赖 AOP 代理,逻辑清晰可控,但需手动处理异常和资源释放。
核心组件:PlatformTransactionManager + TransactionTemplate
Spring 提供了两个主流编程式事务工具:
- TransactionTemplate:推荐首选,封装了模板逻辑,自动处理 commit/rollback,只需关注业务回调
- PlatformTransactionManager + TransactionDefinition + TransactionStatus:更底层,适合极细粒度控制(如自定义回滚判定、跨事务状态传递)
两者都依赖 PlatformTransactionManager 实现类(如 DataSourceTransactionManager),该 Bean 通常由 Spring Boot 自动配置。
用 TransactionTemplate 写一个典型事务块
注入 TransactionTemplate 后,直接调用 execute() 方法:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public Order createOrderWithInventoryCheck(String userId, List<item> items) {
return transactionTemplate.execute(status -> {
try {
// 1. 创建订单主记录(未提交)
Order order = orderMapper.insert(new Order(userId));
// 2. 扣减库存(逐个检查并更新)
for (Item item : items) {
int affected = inventoryMapper.decrease(item.getSkuId(), item.getQuantity());
if (affected == 0) {
status.setRollbackOnly(); // 显式标记回滚
throw new InsufficientInventoryException(item.getSkuId());
}
}
// 3. 更新订单状态为已确认
orderMapper.updateStatus(order.getId(), "CONFIRMED");
return order;
} catch (InsufficientInventoryException e) {
throw e; // 会被外层捕获并触发 rollback
}
});
}</item>
说明:
– status.setRollbackOnly() 可提前终止事务,即使后续没抛异常也会回滚
– 抛出运行时异常(RuntimeException 或其子类)默认触发回滚
– 返回值可直接从回调中传出,无需额外变量
关键配置项要按需设置
TransactionTemplate 支持运行时配置传播行为、隔离级别、超时等,建议在 Bean 定义时区分用途:
- 高一致性要求(如资金操作):设
isolationLevel = ISOLATION_REPEATABLE_READ - 需独立事务(如日志记录不被外层影响):用
propagationBehavior = PROPAGATION_REQUIRES_NEW - 避免长事务阻塞:设
timeout = 30(秒),超时自动回滚 - 部分异常不回滚:通过
setRollbackOnException(Class extends Throwable>)精确控制
什么时候必须用编程式而非 @Transactional
声明式事务基于方法切面,有天然限制;以下情况应选编程式:
- 事务范围要覆盖 if/else 分支中的某一段,而不是整个方法
- 循环内逐条处理,希望某次失败只回滚当前迭代(配合 REQUIRES_NEW)
- 需要在事务执行中动态读取数据库状态再决定是否继续
- 调用第三方服务前开启事务,服务返回后再决定 commit/rollback(例如先发 MQ 消息,再根据下游响应落库)
- 事务内含非 DB 操作(如缓存删除、文件写入),需确保它们与 DB 操作语义一致(虽无法真正回滚,但可统一控制执行时机)
不复杂但容易忽略:编程式事务不会自动传播到子方法调用,所有 DB 操作必须在 execute 回调内部完成,不能拆到外部 private 方法里再调用 —— 那样会脱离当前事务上下文。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










