Spring 源碼分析之事務(wù)3 事務(wù)的提交與回滾

Spring 源碼分析之事務(wù)
Spring 源碼分析之事務(wù)2 TransactionStatus與TransactionInfo
Spring 源碼分析之事務(wù)3 事務(wù)的提交與回滾
我們回顧一下事務(wù)處理的入口邏輯,代碼如下:

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
            final InvocationCallback invocation) throws Throwable {

        ......

        if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
            
            //一:創(chuàng)建事務(wù)
            TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

            Object retVal;
            try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
                //二:調(diào)用業(yè)務(wù):
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // target invocation exception
                //三:目標(biāo)方法發(fā)生異常的處理
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                //四:恢復(fù)當(dāng)前的事務(wù)信息對象也就是TransactionInfo
                cleanupTransactionInfo(txInfo);
            }
            ......
            
            //五:提交事務(wù)
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
        ......
        
    }

今天我們重點(diǎn)關(guān)注第三、四、五步所到的事情。

一、第三步目標(biāo)方法發(fā)生異常的處理completeTransactionAfterThrowing(txInfo, ex)

這里的業(yè)務(wù)邏輯比較簡單:主要就是判斷目標(biāo)發(fā)生發(fā)生的異常類型是不是RuntimeException || ex instanceof Error,如果是就回滾事務(wù),如果不是,則繼續(xù)提交事務(wù)。
源碼如下:

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        
        //如果txInfo.transactionAttribute.rollbackOn(ex)為true,就回滾,否則進(jìn)入else語塊,執(zhí)行commit操作
        if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
            try {
                txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
            }
        }
        else {
            // We don't roll back on this exception.
            // Will still roll back if TransactionStatus.isRollbackOnly() is true.
            try {
                txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
            }
            ......
        }
    }

txInfo.transactionAttribute.rollbackOn(ex)源碼如下:

public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

二、第四步恢復(fù)當(dāng)前的事務(wù)信息對象也就是TransactionInfo,cleanupTransactionInfo()

不管目標(biāo)方法執(zhí)行是否正常不管拋不拋異常,都進(jìn)入finally,恢復(fù)TransactionInfo
源碼如下:

    /**
     * Reset the TransactionInfo ThreadLocal.
     * <p>Call this in all cases: exception or normal return!
     * @param txInfo information about the current transaction (may be {@code null})
     */
    protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
        if (txInfo != null) {
            txInfo.restoreThreadLocalStatus();
        }
    }

這個時候調(diào)用的就是當(dāng)前TransactionInfo 的restoreThreadLocalStatus方法。源碼如下:

        private void restoreThreadLocalStatus() {
            // Use stack to restore old transaction TransactionInfo.
            // Will be null if none was set.
            transactionInfoHolder.set(this.oldTransactionInfo);
        }

不清楚TransactionInfo 的可以看看我寫的spring源碼分析之事務(wù)2

三、第五步提交事務(wù)commitTransactionAfterReturning(txInfo);

如果目標(biāo)方法執(zhí)行沒有問題,則會進(jìn)入事務(wù)的最后一個階段:提交事務(wù)。
commitTransactionAfterReturning()邏輯如下,看到commit方法我們就放心了:

    protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }
    }

查看commit源碼

@Override
public final void commit(TransactionStatus status) throws TransactionException {
    ......
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    //一、如果當(dāng)前事務(wù)設(shè)置了回滾,那么這里就執(zhí)行事務(wù)的回滾操作。
    if (defStatus.isLocalRollbackOnly()) {
        processRollback(defStatus, false);
        return;
    }
    //二、查看全局事務(wù)是否標(biāo)記為了回滾,如果標(biāo)記了則回滾,
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
        if (defStatus.isDebug()) {
            logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
        }
        processRollback(defStatus, true);
        return;
    }
    
    //  三、提交事務(wù)
    processCommit(defStatus);
}

重點(diǎn)看第三步驟processCommit()

/**
 * Process an actual commit.
 * Rollback-only flags have already been checked and applied.
 * @param status object representing the transaction
 * @throws TransactionException in case of commit failure
 */
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    try {
        boolean beforeCompletionInvoked = false;

        try {
            boolean unexpectedRollback = false;
            prepareForCommit(status);
            triggerBeforeCommit(status);
            triggerBeforeCompletion(status);
            beforeCompletionInvoked = true;
            
            //業(yè)務(wù)執(zhí)行完畢之后,如果設(shè)置有回滾點(diǎn),先釋放回滾點(diǎn),業(yè)務(wù)執(zhí)行ok,回滾點(diǎn)也沒有存在的意義了。
            if (status.hasSavepoint()) {
                if (status.isDebug()) {
                    logger.debug("Releasing transaction savepoint");
                }
                unexpectedRollback = status.isGlobalRollbackOnly();
                status.releaseHeldSavepoint();
            }
            else if (status.isNewTransaction()) {   // 判斷當(dāng)前事務(wù)是否是新事務(wù),如果是新事務(wù),就提交事務(wù)
                if (status.isDebug()) {
                    logger.debug("Initiating transaction commit");
                }
                unexpectedRollback = status.isGlobalRollbackOnly();
                
                //此處提交事務(wù),跟進(jìn)doCommit方法內(nèi)部,會發(fā)現(xiàn)調(diào)用的是java.sql.Connection對象的commit方法。
                doCommit(status);
            }
            else if (isFailEarlyOnGlobalRollbackOnly()) {
                unexpectedRollback = status.isGlobalRollbackOnly();
            }

            // Throw UnexpectedRollbackException if we have a global rollback-only
            // marker but still didn't get a corresponding exception from commit.
            if (unexpectedRollback) {
                throw new UnexpectedRollbackException(
                        "Transaction silently rolled back because it has been marked as rollback-only");
            }
        }
        ......

        // Trigger afterCommit callbacks, with an exception thrown there
        // propagated to callers but the transaction still considered as committed.
        //事務(wù)提交之后的一些回調(diào)
        try {
            triggerAfterCommit(status);
        }
        finally {
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
        }

    }
    finally {
        //事務(wù)處理完畢之后做一些清除或恢復(fù)工作
        cleanupAfterCompletion(status);
    }
}

看下cleanupAfterCompletion()方法。

/**
 * Clean up after completion, clearing synchronization if necessary,
 * and invoking doCleanupAfterCompletion.
 * @param status object representing the transaction
 * @see #doCleanupAfterCompletion
 */
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    //第一步:設(shè)置當(dāng)前事務(wù)狀態(tài)已經(jīng)完成
    status.setCompleted();
    if (status.isNewSynchronization()) {
        TransactionSynchronizationManager.clear();
    }
    if (status.isNewTransaction()) {
        //第二步:如果是提交事務(wù)完畢,則移除當(dāng)前線程所持有的Connection 連接,即釋放連接
        doCleanupAfterCompletion(status.getTransaction());
    }
    //第三步:如果是當(dāng)前事務(wù)中有掛起的資源,則在當(dāng)前事務(wù)執(zhí)行完畢之后,恢復(fù)掛起的資源
    if (status.getSuspendedResources() != null) {
        if (status.isDebug()) {
            logger.debug("Resuming suspended transaction after completion of inner transaction");
        }
        Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
        resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
    }
}

至此spring 事務(wù)的分析也差不多完成了,細(xì)節(jié)方面的自己看下源碼就清楚了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容