编程式事务 - TransactionTemplate 与 PlatformTransactionManager 手动控制
概述
Spring Framework 提供了两种事务管理方式:声明式事务(@Transactional)和 编程式事务。声明式事务通过 AOP 拦截自动开启和提交/回滚事务,使用简便但粒度较粗;编程式事务则允许开发者在代码中手动控制事务的边界,提供更细粒度的事务控制能力。
本文深入分析 Spring 编程式事务的两种实现方式——TransactionTemplate 和 PlatformTransactionManager 的直接使用,涵盖 API 设计、源码分析、与声明式事务的对比,以及在大批量处理场景中的实战案例。
1. 编程式事务的两种方式
Spring 编程式事务有两种主要实现途径:
| 方式 | 核心接口/类 | 特点 |
|---|---|---|
| TransactionTemplate | TransactionTemplate、TransactionCallback | 模板方法模式,回调风格,代码简洁 |
| PlatformTransactionManager 直接使用 | PlatformTransactionManager、TransactionStatus | 手动 getTransaction/commit/rollback,最大灵活性 |
两种方式底层共享同一套事务基础设施——PlatformTransactionManager 接口。TransactionTemplate 是对 PlatformTransactionManager 的封装和简化。
依赖配置
@Configuration
public class TransactionConfig {
@Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/demo");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager tm) {
return new TransactionTemplate(tm);
}
}2. TransactionTemplate 的使用方式
TransactionTemplate 提供了三种核心使用方式,适用于不同的场景需求。
2.1 execute — 带返回值的事务执行
@Service
public class UserService {
private final TransactionTemplate transactionTemplate;
private final JdbcTemplate jdbcTemplate;
public UserService(TransactionTemplate transactionTemplate, JdbcTemplate jdbcTemplate) {
this.transactionTemplate = transactionTemplate;
this.jdbcTemplate = jdbcTemplate;
}
public User createUser(String name, String email) {
return transactionTemplate.execute(status -> {
// 在此闭包内的所有数据库操作都在同一事务中执行
jdbcTemplate.update("INSERT INTO users (name, email) VALUES (?, ?)", name, email);
// 查询刚插入的用户(同一事务内可见)
User user = jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE name = ?",
new BeanPropertyRowMapper<>(User.class), name);
// 可以调用其他 Repository 方法
auditLogService.log("create_user", name);
return user;
});
}
}要点:
execute方法接收TransactionCallback<T>回调,返回值类型由泛型指定- 回调中抛出未检查异常(
RuntimeException)时自动回滚 - 回调正常返回时自动提交
2.2 executeWithoutResult — 无返回值的事务执行
@Service
public class OrderService {
private final TransactionTemplate transactionTemplate;
public OrderService(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void updateOrderStatus(Long orderId, String status) {
transactionTemplate.executeWithoutResult(s -> {
// 无返回值的事务操作
orderDao.updateStatus(orderId, status);
inventoryDao.reserveStock(orderId);
// 如果满足回滚条件,可以手动标记回滚
if (inventoryDao.isInsufficient(orderId)) {
s.setRollbackOnly();
}
});
}
}与 execute 的区别:
executeWithoutResult接收Consumer<TransactionStatus>,无返回值- 内部实际调用了
execute,只是忽略返回值
2.3 TransactionCallback 接口
@FunctionalInterface
public interface TransactionCallback<T> {
@Nullable
T doInTransaction(TransactionStatus status);
}与之对应的 TransactionCallbackWithoutResult:
public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {
@Override
@Nullable
public Object doInTransaction(TransactionStatus status) {
doInTransactionWithoutResult(status);
return null;
}
protected abstract void doInTransactionWithoutResult(TransactionStatus status);
}使用 TransactionCallbackWithoutResult 的匿名内部类方式(Java 8 之前的风格):
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
orderDao.updateStatus(orderId, status);
inventoryDao.reserveStock(orderId);
}
});3. TransactionTemplate 的设计分析
3.1 模板方法模式
TransactionTemplate 是 模板方法模式(Template Method Pattern) 的典型应用。模板方法模式的核心思想是:父类定义算法骨架,子类或回调实现具体步骤。
┌─────────────────────────────────────────────┐
│ TransactionTemplate │
│ │
│ execute(callback) { │
│ ① 获取事务 (getTransaction) │ ← 固定步骤
│ ② 执行业务逻辑 (callback.doInTransaction)│ ← 自定义步骤
│ ③ 提交/回滚 (commit/rollback) │ ← 固定步骤
│ } │
└─────────────────────────────────────────────┘模板方法模式的好处:
- 控制反转:框架管理事务生命周期,业务代码只关注逻辑
- 消除重复:避免在每个业务方法中重复书写 getTransaction/commit/rollback
- 一致性保证:确保事务资源正确释放,不会遗漏提交或回滚
3.2 TransactionOperations 接口
TransactionTemplate 实现了 TransactionOperations 接口:
public interface TransactionOperations {
@Nullable
<T> T execute(TransactionCallback<T> action) throws TransactionException;
default void executeWithoutResult(Consumer<TransactionStatus> action) throws TransactionException {
execute(status -> {
action.accept(status);
return null;
});
}
}接口设计的精妙之处:
接口与实现分离:
TransactionOperations定义了事务操作契约,TransactionTemplate是默认实现。用户可以自定义实现该接口以提供不同的事务执行策略。默认方法:
executeWithoutResult通过execute的默认方法实现,减少实现类的负担。易于测试:业务代码可以依赖
TransactionOperations接口而非具体实现,方便单元测试时 Mock。
3.3 事务隔离级别与传播行为设置
// 创建时设置
TransactionTemplate tmpl = new TransactionTemplate(transactionManager);
tmpl.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
tmpl.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
tmpl.setTimeout(30); // 秒
tmpl.setReadOnly(true);
// 或者在 execute 时通过 TransactionCallback 动态调整
transactionTemplate.execute(status -> {
// status 对象可获取当前事务状态信息
boolean isNew = status.isNewTransaction();
boolean hasSavepoint = status.hasSavepoint();
// ... 业务逻辑
return result;
});4. PlatformTransactionManager 手动控制
对于需要最大灵活性的场景,可以直接使用 PlatformTransactionManager 的底层 API。
4.1 基本流程
@Service
public class PaymentService {
private final PlatformTransactionManager transactionManager;
private final TransactionDefinition defaultDefinition;
public PaymentService(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
this.defaultDefinition = new DefaultTransactionDefinition();
}
public void transfer(Long fromId, Long toId, BigDecimal amount) {
// ① 获取 TransactionStatus(事务已在此刻开启)
TransactionStatus status = transactionManager.getTransaction(defaultDefinition);
try {
// ② 执行业务逻辑
accountDao.debit(fromId, amount);
accountDao.credit(toId, amount);
// ③ 提交事务
transactionManager.commit(status);
} catch (Exception ex) {
// ④ 异常时回滚事务
transactionManager.rollback(status);
throw ex; // 重新抛出异常,让调用方感知
}
}
}4.2 精细化的传播行为与隔离级别
public void complexTransactionFlow() {
// 定义事务属性
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
def.setTimeout(10);
TransactionStatus status = transactionManager.getTransaction(def);
// ...
}4.3 编程式事务的嵌套控制
public void nestedTransactionExample() {
// 外层事务
DefaultTransactionDefinition outerDef = new DefaultTransactionDefinition();
outerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus outerStatus = transactionManager.getTransaction(outerDef);
try {
// 外层操作
dao.operationA();
// 内层事务——使用 PROPAGATION_REQUIRES_NEW 会挂起外层事务
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus innerStatus = transactionManager.getTransaction(innerDef);
try {
dao.operationB();
transactionManager.commit(innerStatus);
} catch (Exception e) {
transactionManager.rollback(innerStatus);
// 内层回滚不影响外层
}
// 继续外层操作
dao.operationC();
transactionManager.commit(outerStatus);
} catch (Exception e) {
transactionManager.rollback(outerStatus);
}
}注意
使用 PlatformTransactionManager 手动控制时必须确保 每个 getTransaction 都有且仅有一个 commit 或 rollback,遗漏会导致资源泄漏和事务悬挂。
5. TransactionStatus 接口
TransactionStatus 是事务执行过程中的状态句柄,贯穿事务的整个生命周期。
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
// —— 继承自 TransactionExecution ——
boolean isNewTransaction(); // 是否是一个新事务(非参与已有事务)
boolean isRollbackOnly(); // 是否已被标记为仅回滚
void setRollbackOnly(); // 标记当前事务为仅回滚
// —— 继承自 SavepointManager ——
Object createSavepoint() throws TransactionException;
void rollbackToSavepoint(Object savepoint) throws TransactionException;
void releaseSavepoint(Object savepoint) throws TransactionException;
// —— 继承自 Flushable ——
void flush(); // 刷新底层会话(如 Hibernate Session)
// —— 自有方法 ——
boolean hasSavepoint(); // 当前事务是否持有保存点
}5.1 setRollbackOnly / isRollbackOnly
transactionTemplate.executeWithoutResult(status -> {
try {
process();
} catch (BusinessException e) {
// 标记回滚,但允许方法继续执行
status.setRollbackOnly();
}
// 方法结束后,框架检测到 rollback-only 标记,执行回滚
});使用场景:
- 在回调中捕获异常后不希望立即抛出,而是让框架统一处理回滚
- 检测到业务校验不通过,需要回滚但不想通过异常控制流程
5.2 hasSavepoint
public void checkSavepoint() {
transactionTemplate.execute(status -> {
System.out.println("是新事务吗?" + status.isNewTransaction());
System.out.println("有保存点吗?" + status.hasSavepoint());
// 在 PROPAGATION_NESTED 传播行为下,hasSavepoint() 返回 true
return null;
});
}hasSavepoint() 在 PROPAGATION_NESTED(嵌套事务)场景下特别有用,此时内层事务通过保存点(Savepoint)实现部分回滚。
5.3 flush
transactionTemplate.execute(status -> {
jdbcTemplate.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
// 强制将 SQL 刷新到数据库(对于 Hibernate/JPA 的会话级别缓存尤为重要)
status.flush();
// 此时可以确保数据库中的值已更新,后续查询能看到最新值
BigDecimal balance = jdbcTemplate.queryForObject(
"SELECT balance FROM accounts WHERE id = 1", BigDecimal.class);
return balance;
});flush() 主要用于 ORM 框架(如 Hibernate),强制将持久化上下文中的变更同步到数据库,但仍在当前事务范围内(未提交)。
6. 声明式事务 vs 编程式事务全面对比
| 对比维度 | 声明式事务(@Transactional) | 编程式事务 |
|---|---|---|
| 使用方式 | 注解声明,AOP 拦截,无侵入 | 代码显式控制,侵入性强 |
| 代码简洁性 | ★★★★★ 一行注解搞定 | ★★★☆☆ 需要显式模板回调 |
| 可读性 | ★★★★☆ 声明即意图,但事务边界隐式 | ★★★★★ 事务边界清晰可见 |
| 粒度控制 | ★★★☆☆ 方法级别,无法在方法内分割 | ★★★★★ 可精确到单个数据库操作 |
| 灵活性 | ★★★☆☆ 固定模式,异常即回滚 | ★★★★★ 可在事务中做任意判断 |
| 嵌套事务 | ★★★★☆ 通过 propagation 属性配置 | ★★★★★ 可精细控制内层提交/回滚 |
| 批量处理 | ★☆☆☆☆ 一个方法一个大事务,易超时 | ★★★★★ 可分批提交,防止大事务 |
| 异常控制 | ★★★☆☆ 默认 Runtime 异常回滚 | ★★★★★ 可自定义回滚条件 |
| 测试难度 | ★★★☆☆ 需要 Spring 容器 | ★★★★☆ 可 Mock TransactionOperations |
| AOP 注意事项 | 自调用失效、private 方法失效 | 无此限制 |
| 学习曲线 | ★★★★★ 低 | ★★★★☆ 中等 |
| 适用场景 | 大多数 CRUD 业务方法 | 批量对账、定时任务、复杂工作流 |
6.1 何时选择编程式事务
- 大批量数据处理:如每日对账、数据迁移、批量导入,需要在方法内分批提交
- 复杂的事务边界:一个方法内需要多个独立的事务段
- 条件性回滚:回滚条件复杂,不依赖异常类型
- 需要精确的超时控制:不同操作需要不同的事务超时时间
- 自调用问题:同一类中方法间调用
@Transactional会失效,编程式事务不受影响
6.2 声明式事务的自调用失效问题
@Service
public class MyService {
// 声明式事务 —— 自调用会失效
@Transactional
public void methodA() {
// 事务生效
this.methodB(); // ❌ 事务不生效!AOP 代理不会拦截自调用
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 本应在新事务中执行,但实际在 methodA 的事务中运行
}
// 编程式事务解决方案
private final TransactionTemplate transactionTemplate;
public void methodC() {
transactionTemplate.executeWithoutResult(status -> {
// 事务生效,不受自调用影响
});
}
public void methodD() {
transactionTemplate.executeWithoutResult(status -> {
// 事务生效,不受自调用影响
});
}
}7. TransactionTemplate 源码分析
以下源码分析基于 Spring Framework 5.3.x。
7.1 execute 方法源码
// 类:org.springframework.transaction.support.TransactionTemplate
@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
// 检查事务管理器是否同时是事务定义(即是否实现了 TransactionDefinition 接口)
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
// 某些事务管理器(如 JTA)偏好回调风格,走不同路径
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager)
.execute(this, action);
}
// —— 标准路径 ——
TransactionStatus status = null;
// 1. 获取事务(可能创建新事务或加入已有事务)
status = this.transactionManager.getTransaction(this);
T result;
try {
// 2. 执行业务回调
result = action.doInTransaction(status);
} catch (RuntimeException | Error ex) {
// 3a. 未检查异常 → 回滚事务,然后重新抛出异常
rollbackOnException(status, ex);
throw ex;
} catch (Throwable ex) {
// 3b. 已检查异常 → 同样回滚(TransactionTemplate 对已检查异常也回滚)
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
// 4. 正常完成 → 提交事务
this.transactionManager.commit(status);
return result;
}7.2 rollbackOnException 方法
// 类:org.springframework.transaction.support.TransactionTemplate
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
try {
// 执行回滚
this.transactionManager.rollback(status);
} catch (TransactionSystemException ex2) {
// 回滚本身失败时,将原始异常作为 suppressed 异常附加
ex2.initApplicationException(ex);
throw ex2;
} catch (RuntimeException | Error ex2) {
// 回滚过程中出现其他异常,附加原始异常信息后抛出
ex.addSuppressed(ex2);
throw ex;
}
}7.3 关键设计决策分析
为什么对已检查异常(Checked Exception)也回滚?
在声明式事务(@Transactional)中,默认只有 RuntimeException 和 Error 触发回滚,已检查异常默认提交。但在 TransactionTemplate 的 execute 中,任何异常都会触发回滚。这是因为:
- 编程式事务由开发者手动控制,回调中抛出已检查异常说明业务处理失败
- 如果希望已检查异常不触发回滚,应在回调内部处理而不向外抛出
为什么先回滚再重新抛出异常?
确保异常传播到调用方,调用方能够感知事务失败并采取相应措施(如重试或记录错误日志)。
7.4 TransactionTemplate 的属性配置
public class TransactionTemplate extends DefaultTransactionDefinition
implements TransactionOperations, InitializingBean {
@Nullable
private PlatformTransactionManager transactionManager;
// 继承自 DefaultTransactionDefinition 的核心属性:
// - propagationBehavior (默认 PROPAGATION_REQUIRED)
// - isolationLevel (默认 ISOLATION_DEFAULT)
// - timeout (默认 TIMEOUT_DEFAULT = -1)
// - readOnly (默认 false)
// - name (事务名称)
// 设置事务管理器
public void setTransactionManager(@Nullable PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
// Bean 初始化时校验
@Override
public void afterPropertiesSet() {
if (this.transactionManager == null) {
throw new IllegalArgumentException("'transactionManager' is required");
}
}
}TransactionTemplate 继承 DefaultTransactionDefinition,因此它本身就是一个 TransactionDefinition——这也是为什么源码中可以直接将 this 传给 transactionManager.getTransaction(this)。
8. 实战案例:批量对账中手动控制事务粒度
8.1 问题场景
假设有一个每日对账任务,需要处理 50 万条交易记录。如果在一个事务中处理所有数据:
- 数据库锁范围大,影响其他业务的并发读写
- 事务日志暴增,可能撑满 UNDO 日志空间
- 单个事务执行时间过长,触发数据库
innodb_lock_wait_timeout - 一旦失败,全部回滚,资源浪费巨大
8.2 编程式事务解决方案:批量提交
@Component
public class ReconciliationTask {
private static final int BATCH_SIZE = 1000;
private final TransactionTemplate transactionTemplate;
private final ReconciliationDao reconciliationDao;
private final TradingDao tradingDao;
public ReconciliationTask(TransactionTemplate transactionTemplate,
ReconciliationDao reconciliationDao,
TradingDao tradingDao) {
this.transactionTemplate = transactionTemplate;
this.reconciliationDao = reconciliationDao;
this.tradingDao = tradingDao;
}
/**
* 每日对账主流程:每 BATCH_SIZE 条提交一次事务
*/
public void dailyReconciliation(LocalDate businessDate) {
// 获取待对账的交易 ID 列表
List<Long> tradeIds = tradingDao.getTradeIdsByDate(businessDate);
log.info("待对账交易总数: {}", tradeIds.size());
int total = tradeIds.size();
int processedCount = 0;
int successCount = 0;
int failCount = 0;
// 按批次处理
for (int i = 0; i < total; i += BATCH_SIZE) {
int end = Math.min(i + BATCH_SIZE, total);
List<Long> batchIds = tradeIds.subList(i, end);
try {
// 每批次在一个独立事务中执行
ReconciliationBatchResult result = transactionTemplate.execute(status -> {
ReconciliationBatchResult batchResult = new ReconciliationBatchResult();
for (Long tradeId : batchIds) {
try {
processSingleTrade(tradeId, businessDate);
batchResult.addSuccess();
} catch (Exception e) {
// 单条对账失败,记录错误但不回滚整批
log.error("单笔对账失败, tradeId={}", tradeId, e);
batchResult.addFailure(tradeId, e.getMessage());
}
}
// 记录对账批次结果(与对账操作在同一事务中)
reconciliationDao.saveBatchResult(businessDate, batchResult);
return batchResult;
});
processedCount += batchIds.size();
successCount += result.getSuccessCount();
failCount += result.getFailureCount();
log.info("对账进度: {}/{}", processedCount, total);
} catch (Exception e) {
// 整个批次失败(如数据库连不上了)
log.error("批次对账失败, 起始索引={}, 结束索引={}", i, end, e);
failCount += (end - i);
}
}
log.info("对账完成, 总数={}, 成功={}, 失败={}", total, successCount, failCount);
}
private void processSingleTrade(Long tradeId, LocalDate businessDate) {
// 1. 查询交易系统数据
TradeRecord trade = tradingDao.getTradeById(tradeId);
// 2. 查询第三方/渠道流水
ChannelRecord channel = tradingDao.getChannelRecord(trade.getChannelTxId());
// 3. 比对金额、状态
if (!trade.getAmount().equals(channel.getAmount())) {
// 金额不一致——记录差异,不抛异常
reconciliationDao.saveDifference(tradeId, "金额不一致",
trade.getAmount(), channel.getAmount());
return;
}
// 4. 更新对账状态
tradingDao.updateReconciliationStatus(tradeId, "MATCHED", businessDate);
}
// 批次结果内部类
@Data
private static class ReconciliationBatchResult {
private int successCount;
private int failureCount;
private List<Long> failedTradeIds = new ArrayList<>();
private List<String> errorMessages = new ArrayList<>();
void addSuccess() {
successCount++;
}
void addFailure(Long tradeId, String errorMsg) {
failureCount++;
failedTradeIds.add(tradeId);
errorMessages.add(errorMsg);
}
}
}8.3 设计要点分析
为什么按 1000 条批量提交?
| 批次大小 | 事务时长 | 锁范围 | 内存占用 | 失败影响 |
|---|---|---|---|---|
| 500 | 短 | 小 | 低 | 小 |
| 1000 | 适中 | 适中 | 适中 | 可控 |
| 5000 | 较长 | 较大 | 较高 | 较大 |
| 全部 | 很长 | 极大 | 高 | 全部回滚 |
1000 条是一个经过实践检验的平衡值。实际项目中应根据单条处理的耗时、数据库性能和网络延迟进行调整。
异常处理的三层防御:
- 最内层(
processSingleTrade):单条对账失败只记录差异,不抛出异常,不影响同一批次的其他交易 - 中间层(
TransactionCallback):捕获单条处理的异常,汇总批次结果后继续执行 - 最外层(批次循环):捕获整个批次的事务失败,记录日志后继续下一批次
8.4 进阶:使用 PlatformTransactionManager 实现更精细的控制
@Component
public class AdvancedReconciliationTask {
private static final int BATCH_SIZE = 1000;
private final PlatformTransactionManager transactionManager;
private final ReconciliationDao reconciliationDao;
private static final TransactionDefinition TX_DEF =
new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
public AdvancedReconciliationTask(PlatformTransactionManager transactionManager,
ReconciliationDao reconciliationDao) {
this.transactionManager = transactionManager;
this.reconciliationDao = reconciliationDao;
}
public void processWithExplicitControl(List<Long> tradeIds) {
TransactionStatus status = null;
int count = 0;
try {
for (int i = 0; i < tradeIds.size(); i++) {
// 每批开始时开启事务
if (count == 0) {
status = transactionManager.getTransaction(TX_DEF);
}
// 处理单条数据
processTrade(tradeIds.get(i));
count++;
// 达到批次大小,提交并重置计数
if (count >= BATCH_SIZE || i == tradeIds.size() - 1) {
transactionManager.commit(status);
count = 0;
status = null;
}
}
} catch (Exception e) {
// 回滚当前批次
if (status != null && !status.isCompleted()) {
transactionManager.rollback(status);
}
throw e;
}
}
private void processTrade(Long tradeId) {
// 业务处理
}
}使用 PlatformTransactionManager 直接控制的方式更加灵活,但需要开发者手动管理事务生命周期,务必确保每个 getTransaction 都有对应的 commit 或 rollback。
总结
Spring 编程式事务是声明式事务的重要补充,在以下场景中不可替代:
- 批量大数据处理:分批提交防大事务
- 复杂事务边界:方法内多个独立事务段
- 条件性回滚:非异常驱动的回滚决策
- 绕过 AOP 限制:自调用、private 方法不受影响
TransactionTemplate通过模板方法模式封装了事务的开启/提交/回滚,推荐在大多数编程式事务场景中使用PlatformTransactionManager直接使用提供最大灵活性,适用于需要精细控制事务嵌套和传播行为的场景- 两者底层共享同一套事务抽象,可以混用
在 Spring 应用中,推荐优先使用声明式事务处理常规业务方法,当遇到上述特殊场景时,以编程式事务作为补充,形成完整的事务管理策略。
参考资料
- Spring Framework Documentation — Transaction Management
- Spring Framework 5.3.x 源码:
org.springframework.transaction.support.TransactionTemplate - Spring Framework 5.3.x 源码:
org.springframework.transaction.PlatformTransactionManager - Spring Framework 5.3.x 源码:
org.springframework.transaction.TransactionStatus