今天开始我们分析一下Spring事务框架最为重要、也是最为复杂的一部分:事务管理器TransactionManager。

事务管理器TransactionManager

先看TransactionManager的定义:

/**
 * Marker interface for Spring transaction manager implementations,
 * either traditional or reactive.
 *
 * @author Juergen Hoeller
 * @since 5.2
 * @see PlatformTransactionManager
 * @see ReactiveTransactionManager
 */
public interface TransactionManager {

}

Spring 5.2才引入的,是为了实现Spring transaction manager的一个marker interface,他应该可以包含两个方向的实现,一个是traditional的,一个是reactive。

我们要研究的是traditional的,暂时不管reactive。

image.png

从PlatformTransactionManager开始。

PlatformTransactionManager

This is the central interface in Spring's imperative transaction infrastructure. Applications can use this directly, but it is not primarily meant as an API: Typically, applications will work with either TransactionTemplate or declarative transaction demarcation through AOP.
For implementors, it is recommended to derive from the provided org.springframework.transaction.support.AbstractPlatformTransactionManager class, which pre-implements the defined propagation behavior and takes care of transaction synchronization handling. Subclasses have to implement template methods for specific states of the underlying transaction, for example: begin, suspend, resume, commit.
The default implementations of this strategy interface are org.springframework.transaction.jta.JtaTransactionManager and org.springframework.jdbc.datasource.DataSourceTransactionManager, which can serve as an implementation guide for other transaction strategies.
Since:
16.05.2003
See Also:
org.springframework.transaction.support.TransactionTemplate, org.springframework.transaction.interceptor.TransactionInterceptor, ReactiveTransactionManager
Author:
Rod Johnson, Juergen Hoeller
JavaDoc特别长,大概是说PlatformTransactionManager是spring事务管理框架中的重要接口,应用可以直接实现这个接口来实现事务管理,但是这个接口并非提供给应用层的API,应用层如果想要通过实现此接口实现spring的事务管理,难度比较大。如果应用层非要自己实现事务控制的话,建议通过继承AbstractPlatformTransactionManager来实现,难度会小一点,因为AbstractPlatformTransactionManager已经实现了包括事务传播机制等相关内容。

下面还是看具体的方法定义吧:

TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
            throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;

接口只包含3个方法:

  1. getTransaction:根据传播机制的定义,获取已经存在的事务或者创建新的事务。
  2. commit:根据事务状态,以及传播机制,提交事务,并检查如果有挂起事务的话,恢复被挂起事务。
  3. rollback:回滚事务,检查如果有挂起事务的话恢复被挂起的事务。

所以我们知道,事务的创建、提交、回滚是通过TransactionManager实现的。

AbstractPlatformTransactionManager

AbstractPlatformTransactionManager实现了上述3个重要方法的绝大部分,只有一小部分需要调用到事务操作的底层比如具体的事务开启、提交、回滚的时候会交给其实现类DataSourceTransactionManager去处理。我们能猜得到这些操作的底层实际和我们自己做编程式事务控制的实现应该是一样的,最终肯定要调用打DataSource、通过数据库连接connection去实现。

下面我们具体分析获取事务getTransaction方法。

开始之前,我们先做一个约定,因为我们知道根据事务传播机制的要求,开启新事务之前需要判断当前是否存在已开启事务,所以,这个过程中我们就要涉及到两个事务,为了方便叙述,我们把方法调用前已经存在的事务叫已开启事务,把当前操作准备要开启的事务叫待开启事务。

getTransaction方法

This implementation handles propagation behavior. Delegates to doGetTransaction, isExistingTransaction and doBegin.
See Also:
doGetTransaction, isExistingTransaction, doBegin
处理事务传播行为,委派给doGetTransaction,isExistingTransaction and doBegin.方法处理。

注意,getTransaction方法的返回是transactionStatus对象,我们从前面对Spring事务框架的分析已经知道,这个TransactionStatus实际是持有transacion事务对象的。

这个方法很长,我们需要将代码截断、按照代码的执行逻辑,逐步分析:

首先获取事务定义,调用doGetTransaction()方法,之后判断是否存在已开启事务,存在的话则调用handleExistingTransaction并返回。

@Override
    public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
            throws TransactionException {
// Use defaults if no transaction definition given.
        TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

        Object transaction = doGetTransaction();
        boolean debugEnabled = logger.isDebugEnabled();

        if (isExistingTransaction(transaction)) {
            // Existing transaction found -> check propagation behavior to find out how to behave.
            return handleExistingTransaction(def, transaction, debugEnabled);
        }

上面这段代码共出现了3个方法,其中doGetTransaction()实际是去处理已开启事务,并非是要处理待开启事务的。然后调用isExistingTransaction判断存在已开启事务的话,则调用handleExistingTransaction并返回。

doGetTransaction和isExistingTransaction

其中doGetTransaction和isExistingTransaction都是在DataSourceTransactionManager中实现的,我们先跳过去看看这两个方法。

首先创建DataSourceTransactionObject对象txObject,并根据当前dataSource设置是否支持savePoint,并创建ConnectionHolder对象交给txObject持有,最后返回txObject对象。

@Override
    protected Object doGetTransaction() {
        DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        txObject.setSavepointAllowed(isNestedTransactionAllowed());
        ConnectionHolder conHolder =
                (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

出现了一个叫ConnectionHolder家伙,先不去具体研究他,实际顾名思义,他估计就是持有数据库链接connection对象的。

我们是不是发现这个方法其实并没有创建事务,只是返回了一个持有ConnectinHolder的txObject对象。

我们先继续往下看他的下一个方法isExistingTransaction,这个方法倒是很简单,根据参数txObject判断他的connectionHolder不为空、并且状态isTransactionActive()为真的话,就认为当前具有已开启事务

protected boolean isExistingTransaction(Object transaction) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
    }

这样的话,如果存在已开启事务的话,就一定存在于这个connectionHolder中。

那我们就需要返回来看一眼上面的这个doGetTransaction()到底是怎么拿到这个connectinHolder的。我们发现他是通过调用TransactionSynchronizationManager.getResource()这个方法获取的。

    @Nullable
    public static Object getResource(Object key) {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        return doGetResource(actualKey);
    }
Retrieve a resource for the given key that is bound to the current thread.
Params:
key – the key to check (usually the resource factory)
Returns:
a value bound to the current thread (usually the active resource object), or null if none
See Also:
ResourceTransactionManager.getResourceFactory()
根据给定的key值获取绑定到当前线程的资源。其中key值通常是资源工厂。

虽然还不知道具体是怎么获取的,但是其他有一点是明确的:获取当前线程的资源,这个资源应该是持有数据库连接的connectionHolder,因为返回虽然是Object对象,但是上面的doGetTransaction在调用之后将他转成了ConnectinHolder。

具体的细节就不需要继续深入了,到这儿已经不影响我们理解本文的主题了。多说一句,TransactionSynchronizationManager是通过ThreadLocal对象保存与当前线程相关的事务对象的,我们现在可以猜测,后面真正获取到待开启事务相关信息之后,待开启事务对象一定会存入这个TransactionSynchronizationManager中的,以便后续的事务处理。

好了,到这儿,我们知道了Spring是怎么判断当前是否存在已开启事务的,接下来我们看一下存在已开启事务的情况下的handleExistingTransaction的处理。

handleExistingTransaction

我们已经知道,handleExistingTransaction方法是在获取到已开启事务之后调用的。
这个方法的源码比较长,我们还是分段分析:

很简单,如果传播机制设置为NERVER的话,抛异常,因为NERVER不允许调用方存在已开启事务

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
            throw new IllegalTransactionStateException(
                    "Existing transaction found for transaction marked with propagation 'never'");
        }

接下来,判断如果事务传播机制为NOT_SUPPORTTED的话,将当前事务挂起,返回一个空事务(当前操作不需要事务):

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
            if (debugEnabled) {
                logger.debug("Suspending current transaction");
            }
            Object suspendedResources = suspend(transaction);
            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
            return prepareTransactionStatus(
                    definition, null, false, newSynchronization, debugEnabled, suspendedResources);
        }

接下来判断如果事务传播机制是REQUIRES_NEW的话,挂起当前事务,并调用startTransaction开启一个新事务:

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 {
                return startTransaction(definition, transaction, debugEnabled, suspendedResources);
            }
            catch (RuntimeException | Error beginEx) {
                resumeAfterBeginException(transaction, suspendedResources, beginEx);
                throw beginEx;
            }
        }

然后是对NESTED的处理,首先判断当前事务管理器是否支持嵌套事务,不支持的话抛出异常。
否则,针对当前以存在、已启动的事务,保存savepoint后,返回。注意,只有针对JTA的事务管理器的实现类(JtaTransactionManager)才会跑进去,暂不关注。

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 (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;
            }
            else {
                // Nested transaction through nested begin and commit/rollback calls.
                // Usually only for JTA: Spring synchronization might get activated here
                // in case of a pre-existing JTA transaction.
                return startTransaction(definition, transaction, debugEnabled, null);
            }
        }

否则,就只剩下事务传播机制SUPPORTS或PROPAGATION_REQUIRED才会跑到下面来。首先判断如果需要对已经存在的事务做校验的话,则校验已启用事务待启用事务的隔离级别是否兼容、待启用事务如果是只读事务则要求已启用事务也必须是只读事务......等,不兼容则抛出异常。

// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (isValidateExistingTransaction()) {
            if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
                Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
                if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
                    Constants isoConstants = DefaultTransactionDefinition.constants;
                    throw new IllegalTransactionStateException("Participating transaction with definition [" +
                            definition + "] specifies isolation level which is incompatible with existing transaction: " +
                            (currentIsolationLevel != null ?
                                    isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
                                    "(unknown)"));
                }
            }
            if (!definition.isReadOnly()) {
                if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
                    throw new IllegalTransactionStateException("Participating transaction with definition [" +
                            definition + "] is not marked as read-only but existing transaction is");
                }
            }
        }

否则,当前操作加入已启用事务

boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

至此,这个handleExistingTransaction方法分析完了,但是要记得还有一个startTransaction没做分析,这个才是真正开启事务的地方。

但是在开始分析startTransaction之前,还是要多说一句,在每一种事务传播机制处理完成之后,都要调用prepareTransactionStatus去准备要返回的TransactionStatus对象,我们知道其最终返回的其实就是我们在Spring事务框架中分析过的TransactionStatus的落地实现DefaultTransactionStatus。其实这个不是我要说的重点,重点是......我们还是先看一眼代码:
prepareTransactionStatus会调用prepareSynchronization:

    protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
        if (status.isNewSynchronization()) {
            TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
            TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
                    definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
                            definition.getIsolationLevel() : null);
            TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
            TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
            TransactionSynchronizationManager.initSynchronization();
        }
    }

看到了吗,创建的事务最终会调用TransactionSynchronizationManager放入到ThreadLocal对象中......如果大家没有忘记的话,判断当前是否存在已开启事务就是通过这个TransactionSynchronizationManager完成的,当然了,已开启事务本来就是由他持有、所以当然是由他来判断了。

下一篇 Spring事务框架之TransactionManager(2)
上一篇 Spring事务框架之TransactionStatus


45 声望17 粉丝