1.简介
TransactionTemplate 是 Spring 框架中用于编程式事务管理的工具类。它简化了事务管理的代码,允许你在代码中显式地控制事务的边界。
1. TransactionTemplate 的主要方法
execute 方法:
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager cpptm) {
return cpptm.execute(this, action);
}
else {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
作用: 执行带有返回值的事务操作。
参数: TransactionCallback<T> 是一个函数式接口,它包含一个 doInTransaction(TransactionStatus status) 方法,你可以在该方法中编写需要在事务中执行的代码。
返回值: 返回 T 类型的值,即事务操作的结果。
TransactionTemplate transactionTemplate = SpringUtils.getBean(TransactionTemplate.class);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
String result = transactionTemplate.execute(status -> {
try {
// 执行业务逻辑
return someService.someMethod();
} catch (Exception e) {
// 触发事务回滚
status.setRollbackOnly();
throw new ServiceException("业务执行失败: " + e.getMessage());
}
});
2.配置方法
TransactionTemplate 还提供了一些配置方法,用于设置事务的传播行为、隔离级别、超时时间等:
setPropagationBehavior(int propagationBehavior): 设置事务的传播行为,例如 PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW 等。
setIsolationLevel(int isolationLevel): 设置事务的隔离级别,例如 ISOLATION_READ_COMMITTED、ISOLATION_SERIALIZABLE 等。
setTimeout(int timeout): 设置事务的超时时间(以秒为单位)。
setReadOnly(boolean readOnly): 设置事务是否为只读事务。
分别对应声明式事物@Transactional中的对应属性;
3. 常见问题与注意事项
事务回滚
-
默认回滚规则: 默认情况下,Spring 只会在遇到
RuntimeException
,Error和Throwable
时回滚事务。如果你希望在遇到检查异常(checked exception)时也回滚事务,可以通过status.setRollbackOnly()
手动设置回滚。 -
手动回滚: 在
execute
方法中,如果捕获到异常并希望回滚事务,可以调用status.setRollbackOnly()
。 -
多次平行调用execute方法,被视为不同的事物,传播行为仅生效在嵌套事务的情况下。下附单元测试概述。
public void testExecute() {
Long entityId = 1888854477837537282L;
// 初始化数据
entityMapper.update(Wrappers.lambdaUpdate(Entity.class)
.eq(Entity::getId, entityId )
.set(Entity::getRemark, "initial remark"));
// 设置传播行为为 PROPAGATION_REQUIRED
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
try {
// 第一次更新(成功)
transactionTemplate.execute(status1 -> {
subtaskMapper.update(Wrappers.lambdaUpdate(Entity.class)
.eq(Entity::getId, entityId )
.set(Entity::getRemark, "remark 1st"));
return null;
});
// 第二次更新(抛出异常)
transactionTemplate.execute(status2 -> {
subtaskMapper.update(Wrappers.lambdaUpdate(Entity.class)
.eq(Entity::getId, subtaskId)
.set(Entity::getRemark, "remark 2nd"));
//或者设置回滚
status2.setRollbackOnly();
return null;
});
} catch (Exception e) {
// 捕获异常,但不处理
}
// 验证数据是否回滚
Entity entity= entityMapper.selectById(entityId );
if (Objects.equals("initial remark", entity.getRemark())) {
log.info("数据应回滚到初始状态");
}
log.info("数据当前状态:{}", entity.getRemark());
//输出数据-->数据当前状态:remark 1st
}
public void testRequired() {
Long entityId = 1888854477837537282L;
// 初始化数据
entityMapper.update(Wrappers.lambdaUpdate(Entity.class)
.eq(Entity::getId, entityId )
.set(Entity::getRemark, "initial remark"));
// 设置传播行为为 PROPAGATION_REQUIRED
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
try {
// 外层事务
transactionTemplate.execute(status -> {
// 第一次更新(在同一个事务中)
subtaskMapper.update(Wrappers.lambdaUpdate(TmsSubtask.class)
.eq(TmsSubtask::getId, subtaskId)
.set(TmsSubtask::getRemark, "remark 1st"));
// 第二次更新(嵌套在同一个事务中)
transactionTemplate.execute(status2 -> {
subtaskMapper.update(Wrappers.lambdaUpdate(TmsSubtask.class)
.eq(TmsSubtask::getId, subtaskId)
.set(TmsSubtask::getRemark, "remark 2nd"));
throw new RuntimeException("模拟异常");
});
return null;
});
} catch (Exception e) {
// 捕获异常
}
// 验证数据是否回滚
Entity entity= entityMapper.selectById(entityId );
if (Objects.equals("initial remark", entity.getRemark())) {
log.info("数据应回滚到初始状态");
}
log.info("数据当前状态:{}", entity.getRemark());
//输出数据-->数据当前状态:initial remark
}
事务传播行为
-
传播行为的选择: 根据业务需求选择合适的传播行为。例如,
PROPAGATION_REQUIRED
表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 -
嵌套事务: 如果你需要嵌套事务,可以使用
PROPAGATION_NESTED
,但要注意数据库和事务管理器是否支持嵌套事务。
事务隔离级别
-
隔离级别的选择: 根据业务需求选择合适的隔离级别。例如,
ISOLATION_READ_COMMITTED
可以避免脏读,但可能会遇到不可重复读和幻读问题。
事务超时
-
超时设置: 如果事务执行时间过长,可能会导致数据库锁争用或资源耗尽。可以通过
setTimeout
方法设置事务的超时时间。