91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring事務執行過程是怎樣的

發布時間:2022-01-10 09:44:29 來源:億速云 閱讀:99 作者:柒染 欄目:網絡安全

Spring事務執行過程是怎樣的,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

先說一下啟動過程中的幾個點: 

  加載配置文件:Spring事務執行過程是怎樣的

 Spring事務執行過程是怎樣的

  AbstractAutowireCapableBeanFactory.doCreateBean --> initializeBean --> applyBeanPostProcessorsAfterInitialization --> beanProcessor.postProcessAfterInitialization --> AbstractAutoProxyCreator.postProcessAfterInitialization --> wrapIfNecessary(bean, beanName, cacheKey) --> getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null)Advisor是Pointcut和Advice的配置器,它包括Pointcut和Advice,是將Advice注入程序中Pointcut位置的代碼;AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary:調用txAdvice上圖的事務通知設置數據源 DataSourceTransactionManager,ChooseDataSource是項目中配置的自定義的繼承至AbstractRoutingDataSource的默認數據源,命名什么的:

Spring事務執行過程是怎樣的

  啟動結束后,發起事務調用,首先攔截方法起CglibAopProxy.intercept --> ReflectiveMethodInvocation.proceed --> ExposeInvocationInterceptor.invoke --> TransactionInterceptor.invoke:

    public Object invoke(final 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);        // Adapt to TransactionAspectSupport's invokeWithinTransaction...
        return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
            @Override            public Object proceedWithInvocation() throws Throwable {                return invocation.proceed();
            }
        });
    }

  TransactionAspectSupport.invokeWithinTransaction :

 Spring事務執行過程是怎樣的

Spring事務執行過程是怎樣的

   determineTransactionManager方法先判斷當前事務有無配置特定事務管理器,如果沒有判斷是否設置過默認的事務管理器,都沒有的情況下:

Spring事務執行過程是怎樣的

    public PlatformTransactionManager getTransactionManager() {        return this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
    }

  接下來判斷加載的事務屬性是否存在或者當前事務管理器是否不是CallbackPreferringPlatformTransactionManager,符合條件會執行到createTransactionIfNecessary,先是:

        if (txAttr != null && txAttr.getName() == null) {
            txAttr = new DelegatingTransactionAttribute(txAttr) {
                @Override                public String getName() {                    return joinpointIdentification;
                }
            };
        }

  DelegatingTransactionAttribute本身除了被實現后使用沒有其他作用。然后從事務管理器中取出事務,doGetTransaction從之前set的數據源取出連接set給DataSourceTransactionObject:

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

  然后判斷事務是否已存在,如果存在例如嵌套事務,會根據定義的傳播方式進行處理,具體處理后面會說,這里是還不存在。然后驗證了一下事務是否超時。由于從事務定義(TransactionDefinition持有隔離級別等事務屬性的對象)中取出的事務傳播方式我這里是默認的 PROPAGATION_REQUIRED,第一句用于掛起事務的什么也沒做,然后或許事務同步為激活同步,接著就到啟動事務了DataSourceTransactionManager doBegin:

            if (txObject.getConnectionHolder() == null ||
                    txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                Connection newCon = this.dataSource.getConnection();                if (logger.isDebugEnabled()) {
                    logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
                }
                txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
            }

  先從數據源中getConnection,set給DataSourceTransactionObject,設置為同步事務,prepareConnectionForTransaction根據配置確定事務是否只讀,被嵌套的事務中前一個的隔離級別txObject.setPreviousIsolationLevel(previousIsolationLevel):

Spring事務執行過程是怎樣的

  判斷是否已設置為自動提交,如果是設置則設置事務對象為自動還原為自動提交,有點拗口,意思大概是當事務復用數據庫連接時第一個事務提交后,同一個連接的下一個事務還是設置為自動提交,否則當前事務如果被設為手痛提交,因為連接池中的連接會被復用,在同一個連接上的后續事務可能需要手動調用conn.commit才能提交下一個事務,設置connection holder代表的連接的事務是活動的;檢查超時;判斷當前事務的連接是否是新創建的,是則注冊給TransactionSynchronizationManager,通過ThreadLocal將線程和事務綁定;prepareSynchronization設置這個事務同步管理器是否包含實際執行的事務,當前線程事務隔離級別、是否只讀以及事務定義名,初始化同步事務(private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations")): 

    public static void initSynchronization() throws IllegalStateException {
        if (isSynchronizationActive()) {
            throw new IllegalStateException("Cannot activate transaction synchronization - already active");
        }
        logger.trace("Initializing transaction synchronization");
        synchronizations.set(new LinkedHashSet<TransactionSynchronization>());
    }

   回到TransactionAspectSupport,prepareTransactionInfo方法創建事務信息,并通過ThreadLocal綁定給當前線程:

        TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
        private void bindToThread() {            // Expose current TransactionStatus, preserving any existing TransactionStatus            // for restoration after this transaction is complete.
            this.oldTransactionInfo = transactionInfoHolder.get();
            transactionInfoHolder.set(this);
        }

 Spring事務執行過程是怎樣的

 Spring事務執行過程是怎樣的

  綁定中保留了當前事務狀態,應該用來在嵌套事務中內層事務完成后恢復外層事務的現場。

  createTransactionIfNecessary結束,回到TransactionAspectSupport的invokeWithinTransaction方法,接下來是invocation.proceedWithInvocation,這個方法上面貼了,new InvocationCallback時實現了這個方法,代碼只有一句調用了MethodInvocation的proceed,也就是環繞通知調用被切方法的方法(也有可能調用其他Interceptor的切面方法),我這直接調用了被切的方法,然而并沒有直接走到后面的completeTransactionAfterThrowing或commitTransactionAfterReturning,也沒有到清理事務信息的方法,因為有嵌套事務,于是被嵌套的切了,與上面過程相同之處就不說了,說說不同的。

  getTransaction這次因為已經存在事務,使用同一個連接,JdbcTransactionObjectSupport實例保存了connectionHolder,所以這次走進了這個判斷分支:

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

  handleExistingTransaction方法內根據不同的事務傳播方式走不同的代碼分支,我這就是默認REQUIRED使用現有事務,所以這個方法基本和沒走也差不多。嵌套的都完了就走到cleanupTransactionInfo方法了,這方法實際調用了TransactionInfo.restoreThreadLocalStatus,實際上還原了之前的事務信息:

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

  然后是commitTransactionAfterReturning:

    /**
     * Execute after successful completion of call, but not after an exception was handled.
     * Do nothing if we didn't create a transaction.
     * @param txInfo information about the current transaction     */
    protected void commitTransactionAfterReturning(TransactionInfo txInfo) {        if (txInfo != null && txInfo.hasTransaction()) {            if (logger.isTraceEnabled()) {
                logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }
    }

  commit方法在AbstractPlatformTransactionManager中,先提交的是內層的事務,這里需要提的,嵌套事務的子事務報錯但沒有拋給外層事務,可能會出現rollback-only的問題,defStatus.isLocalRollbackOnly()就是判斷是否有內層事務出錯設置rollbackOnly為true了,另外,關于全局事務,似乎說的是用的兩段式XA?,不過目前用不上,只是一個連接對數據庫,這里可以考慮下。該到具體處理提交的方法processCommit了。同樣在AbstractPlatformTransactionManager中。prepareForCommit方法是空的,protected應該是準備給子類重寫的,或者這就是我要找的。savepoint沒有,由于是內層事務,triggerBeforeCommit、triggerBeforeCompletion、triggerAfterCommit和triggerAfterCommit方法沒有執行,設置事務狀態后,這個內層事務就提交完了。

  ExposeInvocationInterceptor(可以暴露出攔截器鏈,一般用不到它,用到時應該在鏈首)還原外層被攔截方法的執行:

    @Override    public Object invoke(MethodInvocation mi) throws Throwable {
        MethodInvocation oldInvocation = invocation.get();
        invocation.set(mi);        try {            return mi.proceed();
        }        finally {
            invocation.set(oldInvocation);
        }
    }

  這個外層就是實際被攔截的方法,會通過CglibAopProxy執行。

  再來就是提交外層事務了,cleanupTransactionInfo的old這次是null了,一樣的流程就不說了,由于外層事務是創建了同步對象所以triggerBeforeCommit執行了:

TransactionSynchronizationUtils.triggerBeforeCommit(status.isReadOnly());
    public static void triggerBeforeCommit(boolean readOnly) {        for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) {
            synchronization.beforeCommit(readOnly);
        }
    }

  這里的beforeCommit由于我用的是mybatis,所以如果執行的話,會執行到SqlSessionUtils.beforeCommit,然而由于SqlSessionUtils是不能被繼承的,所以這里不太好動手腳,只能在這個類的外層想辦法。triggerBeforeCompletion是類似的。外層事務會有獲取status.isGlobalRollbackOnly()用于doCommit(status)之后是否報錯,注意,就是說其實并不會打斷提交的執行。doCommit(status):

    @Override    protected void doCommit(DefaultTransactionStatus status) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
        Connection con = txObject.getConnectionHolder().getConnection();        if (status.isDebug()) {
            logger.debug("Committing JDBC transaction on Connection [" + con + "]");
        }        try {
            con.commit();
        }        catch (SQLException ex) {            throw new TransactionSystemException("Could not commit JDBC transaction", ex);
        }
    }

Spring事務執行過程是怎樣的

  沒錯,我們用的是druid,這里不需要解釋了。之后就是一些完成回調,各種解綁、clear、reset了,之前設置的必須還原為自動提交會在doCleanupAfterCompletion還原,最后關閉連接。

關于Spring事務執行過程是怎樣的問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

邹城市| 长白| 潮州市| 德州市| 中牟县| 阿瓦提县| 伊宁市| 富源县| 襄城县| 牡丹江市| 化隆| 南投市| 师宗县| 肇源县| 富川| 偃师市| 扎囊县| 历史| 仙游县| 镇安县| 汽车| 曲周县| 德兴市| 会同县| 宝兴县| 洛南县| 九龙城区| 拜泉县| 武川县| 无为县| 邵阳县| 枞阳县| 徐汇区| 普定县| 吉首市| 诸城市| 朝阳县| 民丰县| 东乡县| 崇礼县| 石首市|