Spring源碼解讀(三)事務 一、spring事務簡介 二、編程式事務TransactionTemplate 三、聲明式事務@Transactional 四、事務的核心源碼

一、spring事務簡介

spring中有兩種事務實現方式:

1)編程式事務
使用TransactionTemplate,實現更加細粒度的事務控制。

2)聲明式事務
使用@Transactional,無代碼侵入的事務使用方式。通過AOP實現,本質是在方法前後進行攔截,簡單描述就是在方法開始前開啓事務,結束後進行提交或者回滾。

二、編程式事務TransactionTemplate

下面看下類圖:

如上圖所示,發現其實現了TransactionOperrations和InitializingBean兩個接口,繼承自DefaultTransactionDefinition。分別看下都是幹嘛的。

TransactionOperations內部是執行事務回調的方法,分別提供有返回值和沒有返回值的兩個方法。

InitializingBean是spring在bean初始化時預留的接口,專門用來在bean屬性加載完成後用來執行的方法。

下面我們看看TransactionTemplate分別實現的這兩個接口的哪些方法:

    @Override
    public void afterPropertiesSet() {
        //事務管理器是否爲空
        if (this.transactionManager == null) {
            throw new IllegalArgumentException("Property 'transactionManager' is required");
        }
    }


    @Override
    @Nullable
    public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
        //內部封裝的事務管理器
        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
        }
        else {
            //手動獲取事務,執行方法,提交事務管理器
            //1、獲取事務
            TransactionStatus status = this.transactionManager.getTransaction(this);
            T result;
            try {
                //2、執行業務邏輯
                result = action.doInTransaction(status);
            }
            catch (RuntimeException | Error ex) {
                // 應用運行時異常-》回滾
                rollbackOnException(status, ex);
                throw ex;
            }
            catch (Throwable ex) {
                // 未知異常-》回滾
                rollbackOnException(status, ex);
                throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
            }
            //、事務提交
            this.transactionManager.commit(status);
            return result;
        }
    }

三、聲明式事務@Transactional

聲明式事務的核心就是TransactionInterceptor

如上圖所示,事務攔截器的攔截功能就是依靠實現了MethodInterceptor接口,這個是spring的方法攔截器。一個函數式接口,只有一個invoke方法。

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {

    /**
     * Implement this method to perform extra treatments before and
     * after the invocation. Polite implementations would certainly
     * like to invoke {@link Joinpoint#proceed()}.
     * @param invocation the method invocation joinpoint
     * @return the result of the call to {@link Joinpoint#proceed()};
     * might be intercepted by the interceptor
     * @throws Throwable if the interceptors or the target object
     * throws an exception
     */
    @Nullable
    Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;

}

看下其方法的實現:

    @Override
    @Nullable
    public Object invoke(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);
        
        // 調用TransactionAspectSupport的invokeWithinTransaction方法
        return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }

下面主要關注invokeWithinTransaction方法,只註釋主要的方法:

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

        // 如果事務屬性爲空,則該方法是非事務性的。
        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        final TransactionManager tm = determineTransactionManager(txAttr);

        if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
            ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
                if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
                    throw new TransactionUsageException(
                            "Unsupported annotated transaction on suspending function detected: " + method +
                            ". Use TransactionalOperator.transactional extensions instead.");
                }
                ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
                if (adapter == null) {
                    throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
                            method.getReturnType());
                }
                return new ReactiveTransactionSupport(adapter);
            });
            return txSupport.invokeWithinTransaction(
                    method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
        }

        PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
        // 聲明式事務
        if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
            // 使用 getTransaction 和 commit/rollback 調用進行標準事務劃分。
            TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

            Object retVal;
            try {
                // 業務代碼
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // 捕獲異常,回滾或提交事務
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                //清空緩存的事務信心,並設置當前線程的事務信息爲老的,即首次進入方法獲取的事務
                cleanupTransactionInfo(txInfo);
            }

            if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
                // Set rollback-only in case of Vavr failure matching our rollback rules...
                TransactionStatus status = txInfo.getTransactionStatus();
                if (status != null && txAttr != null) {
                    retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                }
            }
            // 返回結果之前,進行事務提交
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
        //編程式事務
        else {
            Object result;
            final ThrowableHolder throwableHolder = new ThrowableHolder();

            // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
            try {
                result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
                    TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
                    try {
                        Object retVal = invocation.proceedWithInvocation();
                        if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
                            // Set rollback-only in case of Vavr failure matching our rollback rules...
                            retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                        }
                        return retVal;
                    }
                    catch (Throwable ex) {
                        if (txAttr.rollbackOn(ex)) {
                            // A RuntimeException: will lead to a rollback.
                            if (ex instanceof RuntimeException) {
                                throw (RuntimeException) ex;
                            }
                            else {
                                throw new ThrowableHolderException(ex);
                            }
                        }
                        else {
                            // A normal return value: will lead to a commit.
                            throwableHolder.throwable = ex;
                            return null;
                        }
                    }
                    finally {
                        cleanupTransactionInfo(txInfo);
                    }
                });
            }
            catch (ThrowableHolderException ex) {
                throw ex.getCause();
            }
            catch (TransactionSystemException ex2) {
                if (throwableHolder.throwable != null) {
                    logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    ex2.initApplicationException(throwableHolder.throwable);
                }
                throw ex2;
            }
            catch (Throwable ex2) {
                if (throwableHolder.throwable != null) {
                    logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                }
                throw ex2;
            }

            // Check result state: It might indicate a Throwable to rethrow.
            if (throwableHolder.throwable != null) {
                throw throwableHolder.throwable;
            }
            return result;
        }
    }

3.1 createTransactionIfNecessary

    protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
            @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

        // 如果未指定名稱,則應用方法標識作爲事務名稱
        if (txAttr != null && txAttr.getName() == null) {
            txAttr = new DelegatingTransactionAttribute(txAttr) {
                @Override
                public String getName() {
                    return joinpointIdentification;
                }
            };
        }
        //初始化事務的狀態
        TransactionStatus status = null;
        if (txAttr != null) {
            if (tm != null) {
                // 獲取事務狀態
                status = tm.getTransaction(txAttr);
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                            "] because no transaction manager has been configured");
                }
            }
        }
        // 事務爲空,創建新事務
        return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
    }

prepareTransactionInfo

    protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
            @Nullable TransactionAttribute txAttr, String joinpointIdentification,
            @Nullable TransactionStatus status) {

        // 創建一個事務
        TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
        if (txAttr != null) {
            // We need a transaction for this method...
            if (logger.isTraceEnabled()) {
                logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }
            // The transaction manager will flag an error if an incompatible tx already exists.
            txInfo.newTransactionStatus(status);
        }
        else {
            // The TransactionInfo.hasTransaction() method will return false. We created it only
            // to preserve the integrity of the ThreadLocal stack maintained in this class.
            if (logger.isTraceEnabled()) {
                logger.trace("No need to create transaction for [" + joinpointIdentification +
                        "]: This method is not transactional.");
            }
        }

        // 將事務綁定到線程
        txInfo.bindToThread();
        return txInfo;
    }

bindToThread

        private void bindToThread() {
            // 獲取當前事務信息並保存爲舊的,以便日後進行恢復
            this.oldTransactionInfo = transactionInfoHolder.get();
            // 將當前事務綁定到當前持有者,transactionInfoHolder是一個ThreadLocal
            transactionInfoHolder.set(this);
        }

3.2 invocation.proceedWithInvocation() 回調業務代碼

    @FunctionalInterface
    protected interface InvocationCallback {

        @Nullable
        Object proceedWithInvocation() throws Throwable;
    }

上面的接口實現其實是下面的方法,最終實現類是ReflectiveMethodInvocation:

如上圖,ReflectiveMethodInvocation類實現了ProxyMethodInvocation接口,但是ProxyMethodInvocation繼承了3層接口ProxyMethodInvocation -> MethodInvocation -> Invocation -> Joinpoint

Joinpoint:連接點接口,定義了執行接口:Object proceed() throws Throwable;
執行當前連接點,並跳到攔截器鏈上的下一個攔截器。

Invocation:調用接口,繼承自Joinpoint,定義了獲取參數接口: Object[] getArguments();
是一個帶參數的、可被攔截器攔截的連接點。

MethodInvocation:方法調用接口,繼承自Invocation,定義了獲取方法接口:Method getMethod();
是一個帶參數的可被攔截的連接點方法。

ProxyMethodInvocation:代理方法調用接口,繼承自MethodInvocation,定義了獲取代理對象接口:Object getProxy();
是一個由代理類執行的方法調用連接點方法。

ReflectiveMethodInvocation:實現了ProxyMethodInvocation接口,自然就實現了父類接口的的所有接口。
獲取代理類,獲取方法,獲取參數,用代理類執行這個方法並且自動跳到下一個連接點

**proceed() **

    @Override
    @Nullable
    public Object proceed() throws Throwable {
        // 我們從 -1 的索引開始並提前增加。
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // 這裏進行動態方法匹配校驗,靜態的方法匹配早已經校驗過了
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // 動態匹配失敗,跳過當前攔截,進入下一個攔截器
                return proceed();
            }
        }
        else {
            // 它是一個攔截器,所以我們只需調用它:在構造這個對象之前,切入點將被靜態計算
            // 這就是回調我們業務方法
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

3.3 completeTransactionAfterThrowing方法

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            if (logger.isTraceEnabled()) {
                logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
                        "] after exception: " + ex);
            }
            if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
                try {
                    // PlatformTransactionManager的rollback方法
                    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                }
                catch (TransactionSystemException ex2) {
                    logger.error("Application exception overridden by rollback exception", ex);
                    ex2.initApplicationException(ex);
                    throw ex2;
                }
                catch (RuntimeException | Error ex2) {
                    logger.error("Application exception overridden by rollback exception", ex);
                    throw ex2;
                }
            }
            else {
                // 我們不會回滾這個異常
                // 如果 TransactionStatus.isRollbackOnly() 爲真,仍將回滾
                try {
                    // PlatformTransactionManager的commit方法
                    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                }
                catch (TransactionSystemException ex2) {
                    logger.error("Application exception overridden by commit exception", ex);
                    ex2.initApplicationException(ex);
                    throw ex2;
                }
                catch (RuntimeException | Error ex2) {
                    logger.error("Application exception overridden by commit exception", ex);
                    throw ex2;
                }
            }
        }
    }

其實無論是聲明式事務還是編程式事務,都是走的PlatformTransactionManager的getTranscation(),commit(),rockback()。

四、事務的核心源碼

基於前面的簡單分析,我們能夠得出結論,PlatformTransactionManager就是整個spring事務的核心接口:

public interface PlatformTransactionManager extends TransactionManager {

        /**
         * 根據指定的傳播行爲,返回當前活動的事務或創建一個新事務。
         * 請注意,隔離級別或超時等參數僅適用於新事務,因此在參與活動事務時會被忽略。
         * 此外,並非每個事務管理器都支持所有事務定義設置:當遇到不支持的設置時,正確的事務管理器實現應該拋出異常。
         * 上述規則的一個例外是隻讀標誌,如果不支持顯式只讀模式,則應忽略該標誌。 本質上,只讀標誌只是潛在優化的提示。
     */
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
            throws TransactionException;

        /**
         * 提交給定的事務根據其狀態。 
         * 如果事務以編程方式標記爲僅回滾,則執行回滾。
         * 如果事務不是新事務,則省略提交以正確參與周圍的事務。 
         * 如果先前的事務已暫停以便能夠創建新事務,則在提交新事務後恢復先前的事務。
         * 注意,當提交調用完成時,無論是正常還是拋出異常,都必須完全完成並清理事務
        */
    void commit(TransactionStatus status) throws TransactionException;

        /**
         * 執行給定事務的回滾。
         * 如果事務不是新事務,只需將其設置爲僅回滾,以便正確參與周圍的事務。 
         * 如果先前的事務已暫停以能夠創建新事務,則在回滾新事務後恢復先前的事務。
         * 如果提交引發異常,則不要在事務上調用回滾。 
         * 即使在提交異常的情況下,事務也將在提交返回時已經完成並清理。 
         * 因此,提交失敗後的回滾調用將導致 IllegalTransactionStateException
         */
    void rollback(TransactionStatus status) throws TransactionException;

4.1 getTransaction

大概的調用流程如下:


代碼如下:

    /**
     * This implementation handles propagation behavior. Delegates to
     * {@code doGetTransaction}, {@code isExistingTransaction}
     * and {@code doBegin}.
     * 此實現處理傳播行爲。 委託doGetTransaction 、 isExistingTransaction和doBegin
     * @see #doGetTransaction
     * @see #isExistingTransaction
     * @see #doBegin
     */
    @Override
    public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
            throws TransactionException {

        // 如果沒有給出事務定義,則使用默認值。
        TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

        // DataSourceTransactionManager實現doGetTransaction方法,獲取事務
        Object transaction = doGetTransaction();
        boolean debugEnabled = logger.isDebugEnabled();

        // 找到事務
        if (isExistingTransaction(transaction)) {
            // 找到現有事務 -> 檢查傳播行爲以瞭解行爲方式
            return handleExistingTransaction(def, transaction, debugEnabled);
        }

        // Check definition settings for new transaction.
        if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
        }

        // 沒找到現有事務 -> 檢查傳播行爲以瞭解行爲方式
        if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
            throw new IllegalTransactionStateException(
                    "No existing transaction found for transaction marked with propagation 'mandatory'");
        }
        //如果事務傳播機制是以下三種:required,requires_new,nested,則新建事務
        else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
                def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
                def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
            SuspendedResourcesHolder suspendedResources = suspend(null);
            if (debugEnabled) {
                logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
            }
            try {
                //開啓一個事務
                return startTransaction(def, transaction, debugEnabled, suspendedResources);
            }
            catch (RuntimeException | Error ex) {
                resume(null, suspendedResources);
                throw ex;
            }
        }
        else {
            // 當前不存在事務,且傳播機制=PROPAGATION_SUPPORTS/PROPAGATION_NOT_SUPPORTED/PROPAGATION_NEVER,這三種情況
            if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
                logger.warn("Custom isolation level specified but no actual transaction initiated; " +
                        "isolation level will effectively be ignored: " + def);
            }
            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
            return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
        }
    }

doGetTransaction:

    @Override
    protected Object doGetTransaction() {
        // 創建一個數據源事務管理對象
        DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        // 設置是否允許嵌套事務,默認是false
        txObject.setSavepointAllowed(isNestedTransactionAllowed());
        // 獲取jdbc連接
        ConnectionHolder conHolder =
                (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

isExistingTransaction:

    @Override
    protected boolean isExistingTransaction(Object transaction) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        //是否持有鏈接 和 是否存在事務
        return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
    }

startTransaction

    /**
     * Start a new transaction.
     */
    private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
            boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

        // 默認不開啓事務同步
        boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        // 根據給定參數創建一個事務
        DefaultTransactionStatus status = newTransactionStatus(
                definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
        // 開始一個新事務
        doBegin(transaction, definition);
        // 設置事務的名稱,只讀、隔離級別等等
        prepareSynchronization(status, definition);
        return status;
    }

doBegin

    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;

        try {
            // 如果沒有獲取數據庫連接 或者 是個同步事務
            if (!txObject.hasConnectionHolder() ||
                    txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                // 這裏在獲取一次數據連接
                Connection newCon = obtainDataSource().getConnection();
                if (logger.isDebugEnabled()) {
                    logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
                }
                // 設置數據連接
                txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
            }

            // 開啓事務同步
            txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
            // 獲取connection連接
            con = txObject.getConnectionHolder().getConnection();

            // 獲取事務隔離級別
            Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            // 設置事務隔離級別
            txObject.setPreviousIsolationLevel(previousIsolationLevel);
            txObject.setReadOnly(definition.isReadOnly());

            // 如有必要,切換到手動提交。這在某些 JDBC 驅動程序中非常昂貴
            // 所以我們不想做不必要的事情(例如,如果我們已經明確配置連接池來設置它)
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (logger.isDebugEnabled()) {
                    logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
                // 關閉自動提交
                con.setAutoCommit(false);
            }

            prepareTransactionalConnection(con, definition);
            //設置此持有者是代表活動的、由 JDBC 管理的事務。
            txObject.getConnectionHolder().setTransactionActive(true);

            int timeout = determineTimeout(definition);
            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            // 將連接綁定到線程上
            if (txObject.isNewConnectionHolder()) {
                TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
            }
        }

        catch (Throwable ex) {
            if (txObject.isNewConnectionHolder()) {
                //關閉數據鏈接
                DataSourceUtils.releaseConnection(con, obtainDataSource());
                txObject.setConnectionHolder(null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }

到此爲止上面一連串的流程都是基於事務的傳播機制是required,我們除此之外還必須要明白requires_new和nested的過程。

在getTransaction()方法中,由於首次創建,三種方式都是一樣的流程。當事務方法內部的方法仍然使用事務的時候,存在三種不同的情況,主要看getTransaction中下面的方法:handleExistingTransaction(),這個方法我們主要關注required,requires_nes,nested:

requires_new

        //如果事務時requires_new
        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;
            }
        }

suspend方法:

    @Nullable
    protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
        //存在同步
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
            try {
                Object suspendedResources = null;
                if (transaction != null) {
                    //事務不爲空,掛起事務
                    suspendedResources = doSuspend(transaction);
                }
                //獲取當前事務的屬性
                String name = TransactionSynchronizationManager.getCurrentTransactionName();
                TransactionSynchronizationManager.setCurrentTransactionName(null);
                boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
                TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
                Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
                TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
                boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
                TransactionSynchronizationManager.setActualTransactionActive(false);
                //創建一個掛起資源持有者
                return new SuspendedResourcesHolder(
                        suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
            }
            catch (RuntimeException | Error ex) {
                // doSuspend failed - original transaction is still active...
                doResumeSynchronization(suspendedSynchronizations);
                throw ex;
            }
        }
        else if (transaction != null) {
            // 存在事務但是沒有同步,掛起事務
            Object suspendedResources = doSuspend(transaction);
            // 返回掛起資源持有者
            return new SuspendedResourcesHolder(suspendedResources);
        }
        else {
            // 既沒有事務,也沒有同步
            return null;
        }
    }

doSuspend方法:

    @Override
    protected Object doSuspend(Object transaction) {
        //獲取當前事務的數據庫連接對象,並置爲空
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        txObject.setConnectionHolder(null);
        //從當前線程解除給定鍵的資源綁定。
        return TransactionSynchronizationManager.unbindResource(obtainDataSource());
    }

nested:

// nested
        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() + "]");
            }
            // 使用保存點嵌套事務,非JTA走這
            if (useSavepointForNestedTransaction()) {
                // 在現有 Spring 管理的事務中創建保存點,
                // 通過 TransactionStatus 實現的 SavepointManager API。
                // 通常使用 JDBC 3.0 保存點。從不激活 Spring 同步。
                DefaultTransactionStatus status =
                        prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
                //創建一個事務保存點
                status.createAndHoldSavepoint();
                return status;
            }
            else {
                //JTA從這走,開啓一個新事務
                return startTransaction(definition, transaction, debugEnabled, null);
            }
        }

在handleExistingTransaction()存在每種傳播機制的判斷,不滿足的會走最後一行代碼:

        // 不符合上面的傳播行爲,所以走默認的,包含required
        // 關注第三個參數,newTransaction:false,不創建新事務
        return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

4.2 commit

這裏關注invokeWithinTransaction中的commitTransactionAfterReturning方法:

    protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
        // 存在事務就提交,否則什麼都不做
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            if (logger.isTraceEnabled()) {
                logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }
            // 提交
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }
    }
    public final void commit(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;
        // 如果事務明確標記位回滾
        if (defStatus.isLocalRollbackOnly()) {
            if (defStatus.isDebug()) {
                logger.debug("Transactional code has requested rollback");
            }
            // 回滾
            processRollback(defStatus, false);
            return;
        }
        // 如果不需要全局回滾則應該提交 並且 全局回滾
        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;
        }
        // 提交
        processCommit(defStatus);
    }

接下來只關注提交:processCommit(defStatus);

    private void processCommit(DefaultTransactionStatus status) throws TransactionException {
        try {
            boolean beforeCompletionInvoked = false;

            try {
                boolean unexpectedRollback = false;
                //三個前置操作
                // 沒有實現
                prepareForCommit(status);
                // 提交之前回調
                triggerBeforeCommit(status);
                // 完成前回調
                triggerBeforeCompletion(status);
                //設定前置操作完成
                beforeCompletionInvoked = true;

                //如果有保存點,即嵌套事務
                if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        logger.debug("Releasing transaction savepoint");
                    }
                    // 是否是全局回滾
                    unexpectedRollback = status.isGlobalRollbackOnly();
                    // 釋放保存點
                    status.releaseHeldSavepoint();
                }
                // 新事務
                else if (status.isNewTransaction()) {
                    if (status.isDebug()) {
                        logger.debug("Initiating transaction commit");
                    }
                    // 是否是全局回滾
                    unexpectedRollback = status.isGlobalRollbackOnly();
                    // 提交
                    doCommit(status);
                }
                else if (isFailEarlyOnGlobalRollbackOnly()) {
                    // 是否是全局回滾
                    unexpectedRollback = status.isGlobalRollbackOnly();
                }

                // 拋出 UnexpectedRollbackException 如果我們有一個全局僅回滾
                //標記但仍然沒有從提交中獲得相應的異常,手動拋出
                if (unexpectedRollback) {
                    throw new UnexpectedRollbackException(
                            "Transaction silently rolled back because it has been marked as rollback-only");
                }
            }
            catch (UnexpectedRollbackException ex) {
                // 觸發完成後,同步狀態設置爲回滾
                triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
                throw ex;
            }
            catch (TransactionException ex) {
                // 提交失敗則回滾
                if (isRollbackOnCommitFailure()) {
                    doRollbackOnCommitException(status, ex);
                }
                else {
                    // 觸發完成後,同步狀態是未知
                    triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
                }
                throw ex;
            }
            catch (RuntimeException | Error ex) {
                // 如果前三步未完成,調用前置第三個操作
                if (!beforeCompletionInvoked) {
                    triggerBeforeCompletion(status);
                }
                //  提交失敗回滾
                doRollbackOnCommitException(status, ex);
                throw ex;
            }
            try {
                // 觸發後置回調
                triggerAfterCommit(status);
            }
            finally {
                // 事務狀態設置爲已提交
                triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
            }

        }
        finally {
            // 完成後處理事務狀態
            cleanupAfterCompletion(status);
        }
    }

4.3 rollback

前面多次出現completeTransactionAfterThrowing方法,我們進入其內存看看毀掉方法的實現:

// PlatformTransactionManager的rollback方法
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());

AbstractPlatformTransactionManager實現回調

    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, false);
    }

processRollback:

    private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
        try {
            // 默認false
            boolean unexpectedRollback = unexpected;

            try {
                //觸發前置回調
                triggerBeforeCompletion(status);
                //嵌套事務
                if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        logger.debug("Rolling back transaction to savepoint");
                    }
                    //回滾保存點
                    status.rollbackToHeldSavepoint();
                }
                //新事務
                else if (status.isNewTransaction()) {
                    if (status.isDebug()) {
                        logger.debug("Initiating transaction rollback");
                    }
                    //回滾
                    doRollback(status);
                }
                else {
                    // Participating in larger transaction
                    if (status.hasTransaction()) {
                        if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
                            if (status.isDebug()) {
                                logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
                            }
                            doSetRollbackOnly(status);
                        }
                        else {
                            if (status.isDebug()) {
                                logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
                            }
                        }
                    }
                    else {
                        logger.debug("Should roll back transaction but cannot - no transaction available");
                    }
                    // Unexpected rollback only matters here if we're asked to fail early
                    if (!isFailEarlyOnGlobalRollbackOnly()) {
                        unexpectedRollback = false;
                    }
                }
            }
            catch (RuntimeException | Error ex) {
                triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
                throw ex;
            }

            triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

            // Raise UnexpectedRollbackException if we had a global rollback-only marker
            if (unexpectedRollback) {
                throw new UnexpectedRollbackException(
                        "Transaction rolled back because it has been marked as rollback-only");
            }
        }
        finally {
            cleanupAfterCompletion(status);
        }
    }

4.4 cleanupAfterCompletion

這個方法無論是提交還是回滾,都是最後一步需要做的,我們看下其源碼:

    protected void doCleanupAfterCompletion(Object transaction) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

        // 清除線程的資源綁定
        if (txObject.isNewConnectionHolder()) {
            TransactionSynchronizationManager.unbindResource(obtainDataSource());
        }

        // 重置鏈接
        Connection con = txObject.getConnectionHolder().getConnection();
        try {
            // 恢復自動提交
            if (txObject.isMustRestoreAutoCommit()) {
                con.setAutoCommit(true);
            }
            //重置鏈接的只讀和隔離級別
            DataSourceUtils.resetConnectionAfterTransaction(
                    con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
        } catch (Throwable ex) {
            logger.debug("Could not reset JDBC Connection after transaction", ex);
        }

        if (txObject.isNewConnectionHolder()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
            }
            // 關閉數據鏈接
            DataSourceUtils.releaseConnection(con, this.dataSource);
        }
        //清除持有者的屬性
        txObject.getConnectionHolder().clear();
    }

-----------結束:源碼很枯燥,文章寫的一般,感謝大家支持--------------

@Transactional聲明式事務,有什麼短板?

不能在內部使用遠程服務調用,當網絡發生超時,會持續佔用數據庫連接池,不被釋放,持續侵佔連接池資源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章