前言
Spring的事务是依据AOP来实现的,通过AOP从切面来抓捕异常来判断是否回滚以及如何回滚,若是正常返回是是清理事务信息,实施事务提交动作,具体入口代码在TransactionInterceptor里面的invoke方法,代码如下:
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
具体实现细节是invokeWithinTransaction,如下代码所示:
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
基本的实现流程就如上面所阐述的三个阶段,创建事务信息,当发生异常就回滚事务,最后清理事务信息,以及提交事务。
事务状态信息的创建
事务状态信息的创建比较复杂,分为两点来讲,一点是:当已存在事务如何处理,另外一种是不存在事务的处理方式。
已存在事务:
已有事务的创建里面当发现当前事务正在运行,就保存当前事务节点信息,以供后续异常回滚时候按照当前节点进行回滚的需要,如下代码:
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
另外还有一点在这个流程里面比较重要的是:事务的挂起,当需要创建一个新的事务的时候就需要将当前事务挂起,挂起的动作其实就是从当前维护执行事务threadLocal里面去除执行事务并在创建当前事务的时候把去除的事物信息挂载进去,当执行完当前事务之后再提取出来执行,如下代码所示:
public void suspend() {
if (this.holderActive) {
TransactionSynchronizationManager.unbindResource(this.resourceKey);
}
}
。。。。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
catch (Error beginErr) {
resumeAfterBeginException(transaction, suspendedResources, beginErr);
throw beginErr;
}
}
如红色代码标记所示,调用suspend方法挂起当前事务,并退出当前事务资源,保存在新事务里面。当后续提交或者回滚的时候,代码会判断当前是否有挂起事务,有挂起事务就恢复到当前线程,如下代码:
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
doCleanupAfterCompletion(status.getTransaction());
}
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
不存在已有事务: