Spring事务源码分析

118 阅读3分钟

事务属性定义接口

TransactionDefinition是事务属性定义接口,保存事务定义的各种属性,如超时时间、隔离级别、传播属性等。

public interface TransactionDefinition {
    //获取事务传播类型
    int getPropagationBehavior();

    //获取事务隔离级别
    int getIsolationLevel();

    //获取事务超时时间
    int getTimeout();

    //事务的只读性
    boolean isReadOnly();

    //获取事务名称
    String getName();

}

事务实例接口

TransactionStatus是事务实例接口,表示了当前事务在内存中的一个实例,从名字来看保存了事务的运行状态信息。
AbstractTransactionStatus是抽象实现,DefaultTransactionStatus是事务实例的默认实现。

事务管理器

PlatformTransactionManager是Spring事务的核心接口,一般不会直接使用该接口,应用程序可以直接用TransactionTemplate或者AOP进行事务操作。AbstractPlatformTransactionManager是PlatformTransactionManager的抽象类实现。

public interface PlatformTransactionManager {

    //根据事务指定的策略获取激活的事务或者重新创建一个事务。
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    //提交事务
    void commit(TransactionStatus status) throws TransactionException;

    //回滚事务
    void rollback(TransactionStatus status) throws TransactionException;

}

AbstractPlatformTransactionManager定义事务实现的骨架。

获取事务

getTransaction(TransactionDefinition definition)主要逻辑是首先获取当前线程的事务:

        Object transaction = doGetTransaction();

注意doGetTransaction是个钩子方法,负责子类方法的回调,凡是以do开头的方法都类似,后续不在赘述。

如果当前线程已经存在事务,则handleExistingTransaction(definition, transaction, debugEnabled),这个方法根据配置的事务策略处理存在的事务:

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

如果当前线程不存在事务,则开启新事务:

else 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 {
                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
                DefaultTransactionStatus status = newTransactionStatus(
                        definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                doBegin(transaction, definition);
                prepareSynchronization(status, definition);
                return status;
            }
            catch (RuntimeException ex) {
                resume(null, suspendedResources);
                throw ex;
            }
            catch (Error err) {
                resume(null, suspendedResources);
                throw err;
            }

我们选择DataSourceTransactionManager的doBegin看看,里面设置事务为手动提交模式,然后激活当前事务:

// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
            // so we don't want to do it unnecessarily (for example if we've explicitly
            // configured the connection pool to set it already).
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (logger.isDebugEnabled()) {
                    logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
                con.setAutoCommit(false); //设置为手动提交
            }
            txObject.getConnectionHolder().setTransactionActive(true);

事务提交

主要实现方法是processCommit,在事务提交之前还做了其他额外准备操作,然后执行doCommit方法,出错时不会进行资源清理操作,不做回滚操作,回滚操作由调用者发起。

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
        try {
            boolean beforeCompletionInvoked = false;
            try {
                prepareForCommit(status);
                triggerBeforeCommit(status);
                triggerBeforeCompletion(status);
                beforeCompletionInvoked = true;
                boolean globalRollbackOnly = false;
                if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
                    globalRollbackOnly = status.isGlobalRollbackOnly();
                }
                if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        logger.debug("Releasing transaction savepoint");
                    }
                    status.releaseHeldSavepoint();
                }
                else if (status.isNewTransaction()) {
                    if (status.isDebug()) {
                        logger.debug("Initiating transaction commit");
                    }
                    doCommit(status);
                }
                // Throw UnexpectedRollbackException if we have a global rollback-only
                // marker but still didn't get a corresponding exception from commit.
                if (globalRollbackOnly) {
                    throw new UnexpectedRollbackException(
                            "Transaction silently rolled back because it has been marked as rollback-only");
                }
            }
            catch (UnexpectedRollbackException ex) {
                // can only be caused by doCommit
                triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
                throw ex;
            }

            ...

事务回滚

    public final void rollback(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;
        processRollback(defStatus);
    }

事务同步管理器

TransactionSynchronizationManager关键实现是依赖ThreadLocal。各种数据库资源保存在各自线程的副本中,保证线程安全,典型的用空间换时间的做法。

    private static final ThreadLocal<Map<Object, Object>> resources =
            new NamedThreadLocal<Map<Object, Object>>("Transactional resources");

    private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
            new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");

    private static final ThreadLocal<String> currentTransactionName =
            new NamedThreadLocal<String>("Current transaction name");

    private static final ThreadLocal<Boolean> currentTransactionReadOnly =
            new NamedThreadLocal<Boolean>("Current transaction read-only status");

    private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
            new NamedThreadLocal<Integer>("Current transaction isolation level");

    private static final ThreadLocal<Boolean> actualTransactionActive =
            new NamedThreadLocal<Boolean>("Actual transaction active");