Spring笔记(4) - Spring的编程式事务和声明式事务详解
项目背景
项目中一个类中的方法有多个需求由不同的同事负责。比如划分为事务A(TA)和事务B(TB)。TA和TB的数据是没有任何关联的,现在是TB的业务代码错误影响到TA的正常提交导致TA的数据无法写入。该方法使用了@Transactional注解,无法细粒度的控制事务。
所以考虑使用 TransactionTemplate
知识背书
三个重要接口
- PlatformTransactionManager: 事务管理器,用于获取事务,提交回滚事务;
- TransactionDefinition:定义隔离级别,超时时间等
- TransactionStatus:事务运行起来的状态
transactiontemplate使用模板方法,省去了提交事务和回滚事务的代码
使用transactiontemplate,必须首先申明好 datasource 和 transactionmanager 之类的配置,然后spring会自动注入TransactionTemplate这个Bean。
public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean {
@Nullable
private PlatformTransactionManager transactionManager;
//...
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
} else {
TransactionStatus status = this.transactionManager.getTransaction(this);
Object result;
try {
result = action.doInTransaction(status);
} catch (Error | RuntimeException var5) {
this.rollbackOnException(status, var5);
throw var5;
} catch (Throwable var6) {
this.rollbackOnException(status, var6);
throw new UndeclaredThrowableException(var6, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
}
可以看到源码里,TransactionTemplate实现了 InitializingBean。
public void afterPropertiesSet() {
if (this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
说明TransactionTemplate这个bean,在初始化的时候会校验transactionManager是否存在。
同时也看到,execute方法会执行一个新事物,当有异常的时候会调用方法rollbackOnException()回滚事务。最后需要显式的commit事务
落地使用
@Autowired
private TransactionTemplate transactionTemplate;
public void methodA(){
//业务方法
transactionTemplate.executeWithoutResult(status -> {
//业务处理
});
//业务方法
transactionTemplate.executeWithoutResult(status -> {
//业务处理
});
}
目前是使用了不带返回值的内部方法。我看源码是带有异常处理,所以方法块里不用try-catch包围住
基于手动编程transactiontemplate,可以实现多个事务之间相互独立