spring-reading./spring-transaction/spring-transaction-transact.../README.md

164 lines
7.6 KiB
Markdown
Raw Permalink Normal View History

2024-05-28 07:22:28 +00:00
## TransactionTemplate
- [TransactionTemplate](#transactiontemplate)
- [一、基本信息](#一基本信息)
- [二、基本描述](#二基本描述)
- [三、主要功能](#三主要功能)
- [四、最佳实践](#四最佳实践)
- [五、源码分析](#五源码分析)
### 一、基本信息
✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址
** - [github](https://github.com/xuchengsheng/spring-reading)
### 二、基本描述
`TransactionTemplate` 是 Spring Framework 提供的工具类,用于在代码中以编程方式管理事务。它简化了事务的启动、提交/回滚以及异常处理,同时允许灵活配置事务属性,并提供了回调机制以执行特定操作。
### 三、主要功能
1. **事务的启动和提交/回滚**
+ 允许我们以编程方式启动事务,并在需要时提交或回滚事务。这种方式使得我们可以在代码的特定部分明确定义事务的边界,而不必依赖于容器管理。
2. **异常处理**
+ 提供了对异常的处理机制,我们可以通过配置指定在发生异常时应该执行的操作,比如回滚事务。
3. **事务属性的灵活配置**
+ 我们可以使用 `TransactionTemplate` 配置各种事务属性,如隔离级别、传播行为等。这使得我们可以针对不同的场景灵活地配置事务行为。
4. **回调机制**
+ 允许我们定义回调接口,通过这些回调接口,我们可以在事务的不同阶段执行特定的操作。这为更复杂的事务场景提供了更大的灵活性。
### 四、最佳实践
使用 `TransactionTemplate` 来管理事务。它首先创建了一个数据库连接,并通过 `DataSourceTransactionManager`
实例化了 `TransactionTemplate`。在 `TransactionTemplate``execute`
方法中,定义了一个事务回调接口,在该接口的 `doInTransaction` 方法中执行了数据库操作。通过这种方式,可以确保操作要么全部成功提交,要么全部回滚,从而保证数据的一致性和完整性。
```java
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);
}
}
```
运行结果,数据库操作成功完成并成功提交了事务。
```java
新增scores表数据true
```
### 五、源码分析
在`org.springframework.transaction.support.TransactionTemplate#execute`方法中,首先确保了 `PlatformTransactionManager`
已经设置,然后根据事务管理器的类型选择合适的执行方式。如果事务管理器是 `CallbackPreferringPlatformTransactionManager`
的实例,就会调用其 `execute` 方法来执行事务。否则,它将获取事务状态,执行事务回调操作,并在操作过程中处理可能的异常。最后,无论成功还是失败,都会提交事务。
```java
@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`
,然后记录调试日志以表示在应用异常时启动事务回滚。接着尝试执行事务回滚操作,如果发生回滚异常,则记录错误日志,并将原始异常初始化为回滚异常的应用程序异常。最后,如果发生运行时异常或错误,则将其重新抛出。
```java
/**
* 在应用异常时执行回滚,正确处理回滚异常。
* @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;
}
}
```