当然,这期间也会涉及事务定义的应用以及条件检查等逻辑。在所有一切搞定之后,newTransactionStatus会创建一个包含definition、transaction object以及挂起的事务信息和其他状态信息的DefaultTransactionStatus实例并返回。
如果definition定义的传播行为是PROPAGATION_NESTED,根据情况创建嵌套事务,如通过Savepoint或者JTA的TransactionManager。如下:
if(definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if(!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - " + "specify 'nestedTransactionAllowed' property with value 'true'");
}
if(debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if(useSavepointForNesteaTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status = newTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback ca11s.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
doBegin(transaction, definition);
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
}
}
在这种情况下,会首先通过isNestedTransactionAllowed()
方法检查AbstractPlatformTransactionManager的nestedTransactionAllowea属性状态。如果允许嵌套事务,那么还得分两种情况处理。对于DataSourceTransactionManager来说,因为它支持使用Savepoint创建嵌套事务,所以,会使用TransactionStatus创建相应的Savepoint并返回。而JtaTransactionManager则要依赖于具体JTA产品的TransactionManager提供嵌套事务支持。
useSavepointForNestedTransaction()
方法默认返回true,即默认使用Savepoint创建嵌套事务。如果具体子类不支持使用Savepoint创建嵌套事务,则需要覆写该方法,如JtaTransactionManager。如果需要检查事务状态匹配情况,则对当前存在事务与传入的defintion中定义的隔离级别与ReadOnly属性进行检查,如果数据不吻合,则抛出异常。如下:
if(isValidateExistingTransaction()) {
// validate isolation
// validate readonly
}
AbstractPlatformTransactionManager的validateExistingTransaction属性默认值为false。如果你想进一步加强事务属性之间的一致性,可以将validateExistingTransaction属性设置为true,那么这时,以上代码即会被触发执行。剩下的就是在其他情况下,直接构建TransactionStatus返回。比如对应PROPAGATION_SUPPORTS和PROPAGATION_REQUIRED的情况。
(b)如果isExistingTransaction(transaction)
方法返回false,即不存在当前事务的情况下。当definition中定义的传播行为是PROPAGATION_MANDATORY的时候,抛出异常。因为不存在当前事务,所以根据PROPAGATION_MANDATORY的语义,理当如此。当definition中定义的传播行为是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW或者PROPAGATION_NESTED的时候,开启新的事务。如下:
if(definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES__NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if(debugEnabled) {
logger.debug("Creating new transaction with name[" + definition.getName() +"]: " + definition);
}
try {
doBegin(transaction, definition);
}
catch(TransactionException ex) {
resume(null, suspendedResources);
throw ex;
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
之所以在doBegin之前先调用传入null的suspend()
方法,是因为考虑到如果有注册的Synchronization,需要暂时将这些与将要开启的新事务无关的Synchronization先放一边。
剩下的其他情况,则返回不包含任何transaction object的TransactionStatus。这种情况下虽然是空的事务,但有可能需要处理在事务过程中相关的Synchronization。
从getTransaction(TransactionDefinition)的逻辑可以看出,AbstractPlatformTransactionManager更多关注的是事务处理过程中的总体逻辑,而跟具体事务资源相关的处理则交给了具体的子类来实现。
事务处理的完成有两种情况,即回滚事务或者提交事务,AbstractPlatformTransactionManager提供的rollback(TransactionStatus)
和commit(TransactionStatus)
两个模板方法,分别对应这两种情况下的处理。因为事务提交过程中可能需要处理回滚逻辑,我们不妨以commit(TransactionStatus)
的实现流程看一下AbstractPlatformTransactionManager是如何处理事务完成的。
(1)因为在事务处理过程中,我们可以通过TransactionStatus的setRollbackOnly()
方法标记事务回滚,所以,commit(TransactionStatus)
在具体提交事务之前会检查rollBackOnly状态。如果该状态被设置,那么转而执行事务的回滚操作。
rollback(TransactionStatus)
的逻辑主要包含如下3点。
回滚事务。这里的回滚事务又可分为如下3种情况。
如果是嵌套事务,则通过TransactionStatus释放Savepoint。
如果TransactionStatus表示当前事务是一个新的事务,则调用子类的doRollback(TransactionStatus)
方法真正的回滚事务。doRollback(TransactionStatus)
是抽象方法,具体子类必须实现它。DataSourceTransactionManager在实现该方法的时候,无疑是调用connection.rollback()
。HibernateTransactionManager会通过它Session上的Transaction的rollback()
方法回滚事务。其他子类对doRollback(Transactionstatus)
的实现逻辑依此类推。
如果当前存在事务,并且rollbackOnly状态被设置,则调用由子类实现的doSetRollbackOnly(TransactionStatus)
方法,各子类实现通常会将当前的transactionobject的状态设置为rollBackOnly。
触发Synchronization事件。回滚时触发的事件比提交时触发的事件要少,只有triggerBeforeCompletion(status)
和triggerAfterCompletion()
。
清理事务资源。如下所述。
设置TransactionStatus中的completed为完成状态。
清理与当前事务相关的Synchronization。
调用doCleanupAfterCompletion()
释放事务资源,并解除到TransactionSynchronizationManager的资源绑定。对于DataSourceTransactionManager来说,是关闭数据库连接,然后解除对DataSource对应资源的绑定。
如果之前有挂起的事务,恢复挂起的事务。
(2)如果rollBackOnly状态没被设置,则执行正常的事务提交操作。
commit(TransactionStatus)
方法的其他逻辑与rollback(TransactionStatus)
方法基本相似,只是几个具体操作有所差别,如下所述。
决定是否提前检测全局的rollBackOnly标志。如果最外层事务已经被标记为rollBackOnly,并且failEarly0nGlobalRollback0nly为true,则抛出异常(如代码清单19-5所示)。
如果提交事务之前发现TransactionStatus持有Savepoint,则释放它。这实际上是在处理嵌套事务的提交。
如果TransactionStatus表示要提交的事务是一个新的事务,则调用子类的doCommit(TransactionStatus)
方法实现提交事务。doCommit(TransactionStatus)
也是AbstractPlatformTransactionManager公开给子类实现的抽象方法,子类必须实现该方法。对于DataSourceTransactionManager来说,因为事务的提交由Connection决定,所以会直接调用connection.commit()
提交事务。其他的子类也会使用自身的局部事务API在该方法中实现事务的提交。
rollback(TransactionStatus)
中的要多,包括triggerBeforeCommit()、trinrorRoforeCompletion()、triggerAfterCommit()和triggerAfterCompletion()。commit(TransactionStatus)
方法捕获相应异常,并且检测到该字段被设置的时候,需要回滚事务。rollbackOnCommitFailure的默认值是false,表示即使提交过程中出现异常,也不回滚事务。commit(TransactionStatus)
与rollback(TransactionStatus)
一样,都是意味着事务的完成,那么也需要在最后进行事务资源清理的工作,具体内容可以参照rollback(TransactionStatus)
部分。DataSourceTransactionManager事务提交部分代码摘录:
boolean globalRollbackOnly = false;
if(status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
globalRollbackOnly = status.isGlobalRollbackOnly();
}
...
if(globalRollbackOnly) {
throw new UnexpectedRollbackException("Transaction silently rolled back because it has been marked as rollback-only");
}
suspend和resume两个方法的逻辑更好理解了。前者会把TransactionSynchronizationManager上当前事务对应的Synchronization信息以及资源获取到SuspendedResourcesHolder中,然后解除这些绑定。后者则会将SuspendedResourcesHolder中保持的信息重新绑定到TransactionSynchronizationManager。
实际上,如果将AbstractPlatformTransactionManager中处理Synchroniaztion回调以及事务传播行为的逻辑剥离一下的话,就会发现,整个的逻辑流程就是本章开始部分展示的实现原型所表达的那样。
图19-11展示了AbstractPlatformTransactionManager需要子类实现或者覆写的方法。对于各个子类来说,无非就是根据自身需要管理的资源和事务管理API提供这些方法的实现而已。
为了帮助你更容易地理解整个Spring事务管理抽象框架的设计和实现,我们在统一中原的过程中推导并实现了相应的PlatformTransactionManager以及相关原型实现。随后,在原型的基础上,对Spring事务管理抽象框架中的主要类进行了介绍和分析,尤其是对DataSourceTransactionManager的实现做了剖析,以期能够“以点带面”地帮助大家更好地理解Spring事务管理抽象框架中各PlatformTransactionManager通用的实现原理。
在了解了以上内容之后,我们将一起了解一下,在实际开发过程中,如何使用Spring的事务管理抽象框架让我们的日常开发生活变得更加美好。