✒️ 作者 - Lex 📝 博客 - 掘金 📚 **源码地址 ** - github
TransactionTemplate
是 Spring Framework 提供的工具类,用于在代码中以编程方式管理事务。它简化了事务的启动、提交/回滚以及异常处理,同时允许灵活配置事务属性,并提供了回调机制以执行特定操作。
-
事务的启动和提交/回滚
- 允许我们以编程方式启动事务,并在需要时提交或回滚事务。这种方式使得我们可以在代码的特定部分明确定义事务的边界,而不必依赖于容器管理。
-
异常处理
- 提供了对异常的处理机制,我们可以通过配置指定在发生异常时应该执行的操作,比如回滚事务。
-
事务属性的灵活配置
- 我们可以使用
TransactionTemplate
配置各种事务属性,如隔离级别、传播行为等。这使得我们可以针对不同的场景灵活地配置事务行为。
- 我们可以使用
-
回调机制
- 允许我们定义回调接口,通过这些回调接口,我们可以在事务的不同阶段执行特定的操作。这为更复杂的事务场景提供了更大的灵活性。
使用 TransactionTemplate
来管理事务。它首先创建了一个数据库连接,并通过 DataSourceTransactionManager
实例化了 TransactionTemplate
。在 TransactionTemplate
的 execute
方法中,定义了一个事务回调接口,在该接口的 doInTransaction
方法中执行了数据库操作。通过这种方式,可以确保操作要么全部成功提交,要么全部回滚,从而保证数据的一致性和完整性。
public class TransactionTemplateDemo {
public static void main(String[] args) throws SQLException {
// 数据库连接 URL,格式为 jdbc:数据库驱动名称://主机地址:端口号/数据库名称
String url = "jdbc:mysql://localhost:3306/spring-reading";
// 数据库用户名
String username = "root";
// 数据库密码
String password = "123456";
// 创建 SimpleDriverDataSource 对象,用于管理数据源
SimpleDriverDataSource dataSource = new SimpleDriverDataSource(new Driver(), url, username, password);
// 创建 DataSourceTransactionManager 对象,用于管理事务
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
// 创建 JdbcTemplate 对象,用于执行 SQL 语句
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
// 创建事务模板
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
Boolean insertSuccess = transactionTemplate.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
// 主键Id
long id = System.currentTimeMillis();
// 分数
int score = new Random().nextInt(100);
// 保存数据
int row = jdbcTemplate.update("insert into scores(id,score) values(?,?)", id, score);
// 模拟异常,用于测试事务回滚
// int i = 1 / 0;
// 我们也可以使用setRollbackOnly来回滚
// status.setRollbackOnly();
// 返回是否新增成功
return row >= 1;
}
});
System.out.println("新增scores表数据:" + insertSuccess);
}
}
运行结果,数据库操作成功完成并成功提交了事务。
新增scores表数据:true
在org.springframework.transaction.support.TransactionTemplate#execute
方法中,首先确保了 PlatformTransactionManager
已经设置,然后根据事务管理器的类型选择合适的执行方式。如果事务管理器是 CallbackPreferringPlatformTransactionManager
的实例,就会调用其 execute
方法来执行事务。否则,它将获取事务状态,执行事务回调操作,并在操作过程中处理可能的异常。最后,无论成功还是失败,都会提交事务。
@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
// 断言确保已设置PlatformTransactionManager
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
// 如果事务管理器是CallbackPreferringPlatformTransactionManager的实例
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
// 使用CallbackPreferringPlatformTransactionManager执行事务
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
} else {
// 获取事务状态
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
// 执行事务回调操作
result = action.doInTransaction(status);
} catch (RuntimeException | Error ex) {
// 事务中的代码抛出应用程序异常 -> 回滚事务
rollbackOnException(status, ex);
throw ex;
} catch (Throwable ex) {
// 事务中的代码抛出意外异常 -> 回滚事务
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
// 提交事务
this.transactionManager.commit(status);
return result;
}
}
在org.springframework.transaction.support.TransactionTemplate#rollbackOnException
方法中,首先确保已设置了 PlatformTransactionManager
,然后记录调试日志以表示在应用异常时启动事务回滚。接着尝试执行事务回滚操作,如果发生回滚异常,则记录错误日志,并将原始异常初始化为回滚异常的应用程序异常。最后,如果发生运行时异常或错误,则将其重新抛出。
/**
* 在应用异常时执行回滚,正确处理回滚异常。
* @param status 表示事务的对象
* @param ex 抛出的应用程序异常或错误
* @throws TransactionException 如果发生回滚错误
*/
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
// 断言确保已设置PlatformTransactionManager
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
// 打印调试日志,表示在应用异常时启动事务回滚
logger.debug("Initiating transaction rollback on application exception", ex);
try {
// 执行事务回滚
this.transactionManager.rollback(status);
} catch (TransactionSystemException ex2) {
// 打印错误日志,表示应用异常被回滚异常覆盖
logger.error("Application exception overridden by rollback exception", ex);
// 初始化应用程序异常
ex2.initApplicationException(ex);
throw ex2;
} catch (RuntimeException | Error ex2) {
// 打印错误日志,表示应用异常被回滚异常覆盖
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}