Spring事务管理分类:
编程式事务管理
声明式事务管理
事务步骤
- 开启事务
- 执行业务逻辑
- 出现异常进行回滚
- 正常执行则提交事务
编程式事务管理
Spring提供了两种编程式事务管理的方法
- 使用
TransactionTemplate 或者 TransactionalOperator . - 直接实现
TransactionManager 接口
如果是使用的是命令式编程,Spring推荐使用TransactionTemplate 来完成编程式事务管理,如果是响应式编程,那么使用TransactionalOperator 更加合适。
使用TransactionTemplate
使用示例
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}
在上面的例子中,显示的使用了TransactionTemplate 来完成事务管理,通过实现TransactionCallback 回调接口的方式,在doInTransaction 方法中完成相关业务逻辑的处理。(回调机制)
我们看下TransactionTemplate 的execute 方法的实现,分析它是如何实现事务管理的:
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);
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;
}
}
TransactionCallback 回调接口
public interface TransactionCallback<T> {
@Nullable
T doInTransaction(TransactionStatus status);
在回调方法中,我们可以通过TransactionStatus 对象的setRollbackOnly() 方法来 控制事务回滚,如下所示
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly();
}
}
});
TransactionTemplate 实质:(模板模式的思想 + 回调的实现方式)
Spring 中提供了很多 Template 类,比如,JdbcTemplate、RedisTemplate、RestTemplate。尽管都叫作 xxxTemplate,但它们并非基于模板模式来实现的,而是基于回调来实现的,确切地说应该是同步回调。而同步回调从应用场景上很像模板模式,所以,在命名上,这些类使用 Template(模板)这个单词作为后缀;
为什么不用模板模式的方式实现?
在代码实现上,回调相对于模板模式会更加灵活,主要体现在下面几点。
- 像 Java 这种只支持单继承的语言,基于模板模式编写的子类,已经继承了一个父类,不再具有继承的能力。
- 回调可以使用匿名类来创建回调对象,可以不用事先定义类;而模板模式针对不同的实现都要定义不同的子类。
- 如果某个类中定义了多个模板方法,每个方法都有对应的抽象方法,那即便我们只用到其中的一个模板方法,子类也必须实现所有的抽象方法。而回调就更加灵活,我们只需要往需要用到的模板方法中注入回调对象即可。
实现TransactionManager接口
TransactionTemplate 其实也是使用TransactionManager 来完成事务管理的,包括开启事务、提交事务、回滚事务;
Spring对事务的抽象
事务处理的基本步骤
- 开启事务
- 执行业务逻辑
- 出现异常进行回滚
- 正常执行则提交事务
下面是一个基本的JDBC事务管理代码:
Connection con = openConnection();
try {
con.setAutoCommit(false);
con.commit();
} catch (SQLException | MyException e) {
try {
con.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} finally {
try {
con.setAutoCommit(true);
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
如果我们需要更换其他数据访问技术,例如Hibernate、MyBatis、JPA等,虽然事务管理的处理步骤都类似,但API却不同,则需使用相应的API来改写。
Spring 事务的关键是对事务策略的抽象,事务策略由 TransactionManager 接口定义
-
ReactiveTransactionManager ,响应式编程事务管理使用这个接口 -
PlatformTransactionManager ,命令式编程事务管理使用这个接口
Spring把通用的事务处理过程给抽象出来,对外屏蔽 事务底层的具体实现逻辑 ,通过跨不同事务 API 的一致编程模型,使其可以在任何底层事务基础架构上运行;
在Spring事务中,对事务策略抽象的 核心接口是PlatformTransactionManager ,也叫事务管理器,其定义如下:
PlatformTransactionManager
接口定义
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
PlatformTransactionManager 是Spring 命令式编程事务管理的核心接口,定义了完成一个事务所必须的三个步骤,也就是定义了事务实现的规范;
AbstractPlatformTransactionManager 是PlatformTransactionManager 接口的的实现,这个类是Spring提供的一个事务管理的基类,提供了事务管理的模板,它实现了Spring事务管理的一个标准流程。(模板方法模式)
-
判断当前是否已经存在一个事务 -
应用合适的事务传播行为 -
在必要的时候挂起/恢复事务 -
提交时检查事务是否被标记成为rollback-only ,控制 执行真实的回滚/还是执行真实的提交操作 -
触发注册的同步回调
在AbstractPlatformTransactionManager 这个模板类中 ,实现了通用的事务处理逻辑 (实现了 开启事务、提交事务、回滚事务 这三个模板方法),并且在这三个模板方法中 将底层具体的实现定义为抽象方法 交由 子类自己去具体实现;
以commit 方法为例,我们来看下AbstractPlatformTransactionManager 这个模板类是怎么处理的;
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
processCommit(defStatus);
}
在commit 这个模板方法中定义了事务提交的基本逻辑,通过查看status 的事务状态来决定抛出异常还是回滚,或是提交。其中的processRollback 和processCommit 方法也是模板方法,进一步定义了回滚、提交的处理逻辑。
以processCommit 方法为例,具体的提交操作将由抽象方法doCommit 完成。
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
}
protected abstract void doCommit(DefaultTransactionStatus status) throws TransactionException;
doCommit 的具体实现取决于具体的数据访问技术。我们看下JDBC相应的具体实现类DataSourceTransactionManager 中的doCommit 实现。
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
在整个事务处理的过程中,通用的事务处理过程都被抽象到AbstractPlatformTransactionManager 中实现了,
这些公共的事务处理过程是是与 具体事务管理器无关的,事务底层的具体实现逻辑封装在了具体的事务管理器中(比如DataSourceTransactionManager 和HibernateTransactionManager )
用Spring事务API改写后的事务管理代码:
PlatformTransactionManager txManager = getPlatformTransactionManager();
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
无论是使用JDBC、Hibernate还是MyBatis,我们只需要传给txManager 相应的具体实现就可以在多种数据访问技术中切换。
Spring事务通过PlatformTransactionManager 、TransactionDefinition 和TransactionStatus 接口统一事务管理API,并结合模板方法和策略模式决定具体实现。
小结
Spring把通用的事务处理过程给抽象出来, 并且通过定义接口的方式屏蔽事务底层的具体实现逻辑, 应用策略模式 根据具体使用的数据访问技术 来 决定 具体的事务管理API
Spring 通过 提供 跨不同事务 API 的一致编程模型,使其可以在任何底层事务基础架构上运行,例如 Java 事务 API (JTA)、JDBC、Hibernate 和 Java Persistence API (JPA)。
参考:
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#
|