Spring事務源碼分析

事務屬性定義接口

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");
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章