1. 程式人生 > 其它 >Spring 5 原始碼解析- 事務原理分析 - 06

Spring 5 原始碼解析- 事務原理分析 - 06

事務配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xsi:schemaLocation="
       http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <!-- 開啟宣告式事務 --> <tx:annotation-driven /> <!-- 資料來源資訊 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name="driverClassName" value="org.h2.Driver"/> <!-- 資料庫持久化儲存為單個檔案 --> <property name="url" value="jdbc:h2:file:~/.h2/test_db;DB_CLOSE_ON_EXIT=FALSE"/> <!-- 資料庫只在記憶體中執行,關閉連線後資料庫將被清空,適合測試環境--> <!-- <property name="url" value="jdbc:h2:mem:DBName;DB_CLOSE_DELAY=-1"/>--> <property name="username" value="sa"/> <property name="password" value=""/> </bean> <!-- 管理事務的類--> <bean id="transactionManager" class
="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 業務類 --> <bean id="clientServer" class="org.springframework.jdbc.support.learning.transaction.ClientServerImpl" > <property name="dataSource" ref="dataSource" /> </bean> </beans>
View Code

 

一. 配置檔案載入,初始化

    org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

         org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(Element)
               org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(Element,BeanDefinition)
                      NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)
                               org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve

                                    org.springframework.transaction.config.TxNamespaceHandler#init

                                              registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
                                              registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
                                              registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());

     1. 解析事務配置節點資訊。事務節點 <tx:annotation-driven />

     2. 獲取事務節點自定義名稱空間解析處理器 TxNamespaceHandler。

         http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

     3. TxNamespaceHandler 解析處理器初始化。依次註冊事務通知相關的工具類。

      TxAdviceBeanDefinitionParser   解析開啟事務方法的配置解析類,並設定事務屬性。配置比較麻煩,現在一般不使用。推薦使用註解

<!-- 配置事務的傳播特性 --> 
<tx:advice id="txAdvice" transaction-manager="transactionManager"> 
     <tx:attributes> 
     <tx:method name="add*" propagation="REQUIRED"/> 
     <tx:method name="del*" propagation="REQUIRED"/> 
     <tx:method name="modify*" propagation="REQUIRED"/> 
     <tx:method name="*" read-only="true"/> 
     </tx:attributes> 
</tx:advice> 

<!-- 那些類的哪些方法參與事務 --> 
<aop:config> 
      <aop:pointcut id="allManagerMethod" expression="execution(* com.z2sci.soa.manager.*.*(..))"/> 
      <aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice"/> 
</aop:config>
View Code

      AnnotationDrivenBeanDefinitionParser  開啟事務相關的主要類注入。

      org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser#parse(Element element, ParserContext parserContext) 

            org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser#parse(Element element, ParserContext parserContext)
                  org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer#configureAutoProxyCreator(Element element, ParserContext parserContext)
                        org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry, Object)
                                   registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source)

             (1). 註冊事務代理類的建立工具類。 InfrastructureAdvisorAutoProxyCreator

             (2). 註冊事務管理的工具類。

                  org.springframework.transaction.annotation.AnnotationTransactionAttributeSource: 事務屬性註解的配置解析相關。

                  org.springframework.transaction.interceptor.TransactionInterceptor: 事務邏輯處理的主要類。繼承 MethodInterceptor介面,aop代理類呼叫 invoke 方法,進行事務管理。

                  BeanFactoryTransactionAttributeSourceAdvisor 事務邏輯處理切點包裝類 Advisor。 將事務屬性配置(AnnotationTransactionAttributeSource) 和 事務邏輯處理類(TransactionInterceptor)關聯起來。

    /**
     * Inner class to just introduce an AOP framework dependency when actually in proxy mode.
     */
    private static class AopAutoProxyConfigurer {

        public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
            AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

            String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
            if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
                Object eleSource = parserContext.extractSource(element);

                // Create the TransactionAttributeSource definition.
                RootBeanDefinition sourceDef = new RootBeanDefinition(
                        "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
                sourceDef.setSource(eleSource);
                sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

                // Create the TransactionInterceptor definition.
                RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
                interceptorDef.setSource(eleSource);
                interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                registerTransactionManager(element, interceptorDef);
                interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
                String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

                // Create the TransactionAttributeSourceAdvisor definition.
                RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
                advisorDef.setSource(eleSource);
                advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
                advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
                if (element.hasAttribute("order")) {
                    advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
                }
                parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

                CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
                compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
                compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
                compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
                parserContext.registerComponent(compositeDef);
            }
        }
    }
View Code

         

         JtaTransactionManagerBeanDefinitionParser JTA事務配置解析。

 

二. 在方法或類上的事務配置,建立事務代理類

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

      org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)
           org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw)
           org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)
                org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
                     org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization(Object bean, String beanName)
                          org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary(Object bean, String beanName, Object cacheKey)
                               org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean
                               org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

      1. 根據 bean 配置,獲取事務的 攔截器。如果沒找到事務攔截器,則不用生成事務代理類。

                      a. 獲取所有AdvisorBean配置。 BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans()

                      b.查詢滿足條件的AdvisorBean 。事務預設滿足條件的是 BeanFactoryTransactionAttributeSourceAdvisor。

                         判斷主要邏輯:

                         org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor#pointcut切點的匹配方法。

                                   org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches(Method method, Class<?> targetClass)
                                       org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#getTransactionAttribute(Method method,  Class<?> targetClass)

          最終依次尋找並解析目標方法,目標類,目標類父類或父介面上@Transactional 配置。沒找到則不進行事務代理的建立。                                 

                       org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(AnnotatedElement) 

      2. 生成事務管理的代理類。

             a. 解析目標類的所有介面。

             b. 將 公共攔截器 和 上步獲取的攔截器合併。

             c. 進一步判斷 攔截器 是否滿足 Advisor 規範。 Advisor, Advice, MethodInterceptor, MethodBeforeAdviceAdapter, AfterReturningAdviceAdapter, ThrowsAdviceAdapter

             d. 建立代理類。事務預設使用 JdkDynamic 代理實現。生成代理和普通AOP實現類似。

 

三. 代理類呼叫業務方法,同時進行事務處理

      這裡以 JdkDynamic 代理邏輯進行分析。Cglib 代理有部分區別,但事務處理邏輯是使用同一個攔截器。

    org.springframework.jdbc.support.learning.transaction.ClientServer#query(String sql)
           org.springframework.aop.framework.JdkDynamicAopProxy#invoke(Object proxy, Method method, Object[] args)
               org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
               org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

                   org.springframework.transaction.interceptor.TransactionInterceptor#invoke(MethodInvocation invocation) 

     1. 查詢當前呼叫方法的 攔截器(Interceptor) 或 通知(Advice)。事務的預設攔截器是 org.springframework.transaction.interceptor.TransactionInterceptor。

     2. 通過 代理類例項,目標類例項, 目標類class, 呼叫方法,方法引數已經攔截器 建立 ReflectiveMethodInvocation 例項invocation。

     3. 呼叫 org.springframework.aop.framework.ReflectiveMethodInvocation#proceed() 方法,在該方法中再呼叫事務處理方法                                         org.springframework.transaction.interceptor.TransactionInterceptor#invoke(MethodInvocation invocation) 

 

 四. 事務攔截器進行事務的邏輯處理

       org.springframework.transaction.interceptor.TransactionInterceptor#invoke(MethodInvocation invocation) 

              org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction(Method method, Class<?> targetClass,final InvocationCallback invocation) 

        1.  獲得 事務屬性資源資訊(AnnotationTransactionAttributeSource) 例項。

        2.  通過 事務屬性資源資訊 例項獲取 目標方法 或 目標類上 事務屬性(@Transactional)配置資訊例項 txAttr。org.springframework.transaction.interceptor.RuleBasedTransactionAttribute

        3.  通過 事務屬性(@Transactional)配置資訊 獲取 事務管理類例項 tm。當前配置的事務管理器類: org.springframework.jdbc.datasource.DataSourceTransactionManager

        4.  如果是 響應式事務(ReactiveTransactionManager),則進行相關處理。這裡不進行響應事務的邏輯分析。

        5.  將事務管理器 強制轉換成 org.springframework.transaction.PlatformTransactionManager 型別 ptm。

        6.  根據目標方法, 目標類 和 事務屬性配置,獲取事務切入點方法 資訊 joinpointIdentification。org.springframework.jdbc.support.learning.transaction.ClientServerImpl.query

        7.  根據 事務管理器(PlatformTransactionManager) ,事務屬性配置資訊(RuleBasedTransactionAttribute), 事務攔截點(joinpointIdentification) 建立 事務資訊類(TransactionInfo) 例項 txInfo。事務提交時,根據 txInfo 進行事務提交和回滾。 這個單獨分析。org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary(PlatformTransactionManager tm,TransactionAttribute txAttr, String joinpointIdentification) 

        8.  呼叫 org.springframework.transaction.interceptor.TransactionAspectSupport.InvocationCallback#proceedWithInvocation() 方法,最終呼叫目標方法。

        9. 如果方法執行有異常,則進行異常處理。org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex)

        10. 清理事務資訊。 org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo(@Nullable TransactionInfo txInfo)

        11. 如果方法返回值 繼承 io.vavr.control.Try 介面,則 執行 io.vavr.control.Try#onFailure(java.util.function.Consumer<? super Throwable>) 方法,判斷是否需要設定事務回滾。

        11. 事務提交處理,並返回目標方法方法值。 org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning(@Nullable TransactionInfo txInfo)

 

      (一) 建立 事務資訊類(TransactionInfo) 例項 txInfo

            org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction(Method method, Class<?> targetClass, InvocationCallback invocation)
                    org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary(PlatformTransactionManager tm,TransactionAttribute txAttr, String joinpointIdentification)
                         org.springframework.transaction.PlatformTransactionManager#getTransaction(@Nullable TransactionDefinition definition)
                         org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo(PlatformTransactionManager tm,

                                                                                                                                                  TransactionAttribute txAttr, String joinpointIdentification,TransactionStatus status)

                1.設定事務屬性(txAttr)名稱 joinpointIdentification。即呼叫方法全名稱。

                2. 事務管理器(tm) 根據當前配置的事務配置屬性(txAttr) 獲取當前方法事務的狀態。

                        org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction(@Nullable TransactionDefinition definition)
                              org.springframework.transaction.support.AbstractPlatformTransactionManager#doGetTransaction
                              org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

                              org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction(TransactionDefinition definition, Object transaction,boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources)

                              org.springframework.transaction.support.AbstractPlatformTransactionManager#prepareTransactionStatus(TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,boolean newSynchronization, boolean debug, @Nullable Object suspendedResources)

                             (1). 建立 事務物件例項 (transaction),以 Object 型別接受。

                                        設定儲存點標誌為true。(如果是內嵌事務,出現異常時可以將事務回滾到儲存點。)

                                        設定資料庫連線輔助類(ConnectionHolder)例項。 org.springframework.transaction.support.TransactionSynchronizationManager#getResource(Object key)

                             (2). 檢測 建立的事務物件例項 (transaction) 是是否已存在。如果已存在,則按 已存在事務進行事務狀態獲取。                   

                                  org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled)

                                         a.  當前事務配置屬性(txAttr) (DelegatingTransactionDefinition#getPropagationBehavior())是 never 傳播行為,則丟擲異常。never 不容許在事務裡面執行。

                                         b.  當前事務配置屬性(txAttr) (DelegatingTransactionDefinition#getPropagationBehavior())是 not_supported傳播行為,則掛起當前事務(掛起主要將當前事務的資料庫連線資訊置空),建立一個事務狀態,標記為非新建事務。 如果是非同步事務,則通過 TransactionSynchronizationManager 靜態方法設定當前執行緒事務狀態資訊。

                                         c.  當前事務配置屬性(txAttr) (DelegatingTransactionDefinition#getPropagationBehavior())是 requires_new 傳播行為,則掛起當前事務,新開啟一個事務狀態。並設定資料庫連線事務資訊。org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin(Object transaction, TransactionDefinition definition) 。(1)通過資料來源獲取新連線(Connection);(2)設定連線(Connection)只讀屬性標記 和 事務隔離級別。(3)當連線(Connection)是自動提交時,設定為非自動提交。(4) 如果事務時只讀,則通過連線(Connection),設定事務只讀連線。(5)標記當前連線(Connection) 是啟用的。(6) 設定事務超時時間。(7)如果是新建,則繫結連線(Connection)資訊。TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder())

 

                                         d.  當前事務配置屬性(txAttr) (DelegatingTransactionDefinition#getPropagationBehavior())是 nested 傳播行為。(1)內嵌事務支援儲存點,獲得當前連線事務狀態,建立儲存點。底層通過資料庫驅動設定。然後再返回 (2)不支援儲存點,開啟新事務狀態返回。(這種情況主要是針對JTA的處理)

                                         e.  其他 事務配置屬性(txAttr) (DelegatingTransactionDefinition#getPropagationBehavior())是 supports, required  傳播行為,則 獲得當前連線 事務狀態資訊,返回。

                             (3). 判斷如果 當前事務配置屬性(txAttr) (DelegatingTransactionDefinition#getPropagationBehavior())是 mandatory傳播行為,則丟擲異常。 mandatory(必須在已存在的事務裡面執行)

                             (4). 如果 當前事務配置屬性(txAttr) (DelegatingTransactionDefinition#getPropagationBehavior())是 required, requires_new, nested傳播行為, 則掛起當前事情,並建立一個新的事務狀態。

                             (5). 如果 當前事務配置屬性(txAttr) (DelegatingTransactionDefinition#getPropagationBehavior())是其他傳播特性,則 獲得當前連線 事務狀態資訊,返回。

                3. 通過事務管理器(tm), 事務配置屬性(txAttr), 事務狀態 (status) 去建立 事務資訊例項(txInfo)。

              org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo(PlatformTransactionManager tm,TransactionAttribute txAttr, String joinpointIdentification,TransactionStatus status) 

                    (1) 使用 事務管理器(tm), 事務配置屬性(txAttr), 目標方法標識 去建立 事務資訊(TransactionInfo)例項 txInfo。

                    (2) 設定事務資訊(txInfo)中 事務狀態 (status)。

                    (3) 將當前事務資訊(txInfo) 繫結到當前執行緒變數 ThreadLocal<TransactionInfo> transactionInfoHolder。

 

       (二) 執行其他攔截器,AOP通知方法和業務方法。

                      TransactionAspectSupport.InvocationCallback#proceedWithInvocation()

 

       (三) 如果方法執行有異常,則進行異常處理

                org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex)

                      org.springframework.transaction.support.AbstractPlatformTransactionManager#rollback(TransactionStatus status)

                            org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback(DefaultTransactionStatus status, boolean unexpected)

                                org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerBeforeCompletion(DefaultTransactionStatus status)

                                org.springframework.transaction.support.AbstractTransactionStatus#rollbackToHeldSavepoint

                                org.springframework.transaction.support.AbstractPlatformTransactionManager#doRollback(DefaultTransactionStatus status)

                                org.springframework.transaction.support.AbstractPlatformTransactionManager#doSetRollbackOnly(DefaultTransactionStatus status)

                                org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus)

                                org.springframework.transaction.support.AbstractPlatformTransactionManager#cleanupAfterCompletion(DefaultTransactionStatus status)

                1.根據事務狀態(status) ,判斷事務是否已經提交。如果已經提交,則丟擲異常。

                2. 觸發事務完成之前的事件處理。AbstractPlatformTransactionManager#triggerBeforeCompletion(DefaultTransactionStatus status)

                3. 如果事務狀態(status),有儲存點資訊,則事務回滾到到儲存點。底層呼叫資料庫的事務回滾儲存點處理機制。AbstractTransactionStatus#rollbackToHeldSavepoint()

                4. 如果事務狀態(status) 是新建事務,則直接回滾事務。底層呼叫資料庫的事務回滾機制。AbstractPlatformTransactionManager#doRollback(DefaultTransactionStatus status)

                5. 否則 只有 事務狀態(status) ,則設定事務為回滾標記(rollback-only)。

                6. 觸發事務完成之後的事件處理。AbstractPlatformTransactionManager#triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus)

                7. 清理事務完成後  事務狀態(status)  資訊。AbstractPlatformTransactionManager#cleanupAfterCompletion(DefaultTransactionStatus status)

                        (1) 事務狀態(status) 標記事務完成。(2)事務狀態(status) 是新非同步事務,清理非同步事務管理器。(TransactionSynchronizationManager.clear()) (3) 事務狀態(status) 是新建事務,進行事務完成後,後置處理。a.接觸繫結的資料來源資訊。b.恢復資料連線(Connection)為自動提交。c. 恢復連線(Connection)事務隔離級別,只讀屬性。d.釋放連線(Connection)例項。 DataSourceTransactionManager#doCleanupAfterCompletion(Object transaction) 和  DataSourceTransactionManager#doBegin(Object transaction, TransactionDefinition definition)  對應。  (4)當 事務狀態(status) 有掛起事務時,恢復原來掛起的事務。

 

        (四) 清理事務資訊(txInfo) 

                  org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo(@Nullable TransactionInfo txInfo)

                  當前執行緒變數 ThreadLocal<TransactionInfo> transactionInfoHolder 恢復成原來 事務資訊(txInfo) 。

 

          (五)  事務提交處理

                 org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning(@Nullable TransactionInfo txInfo)

                     org.springframework.transaction.support.AbstractPlatformTransactionManager#commit(TransactionStatus status)
                           org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit(DefaultTransactionStatus status)

                1. 檢查 事務狀態(status) ,當前事務狀態(status)  事務已經提交,如果已提交則丟擲異常。

                2. 如果 事務狀態(status)  是回滾標記,則直接回滾當前事務。按回滾事務處理。

                3. 如果 事務狀態(status)  是全域性回滾標記,並且全域性事務回滾不容許提交,則回滾當前事務。按回滾事務處理。

                4. 提交事務處理。

                     org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit(DefaultTransactionStatus status)

                      (1). 事務提交預處理。AbstractPlatformTransactionManager#prepareForCommit(DefaultTransactionStatus status)

                      (2).  觸發事務提交前 處理方法。

                                   AbstractPlatformTransactionManager#triggerBeforeCommit(DefaultTransactionStatus status)

                                       TransactionSynchronizationUtils.triggerBeforeCommit(status.isReadOnly())

                                            TransactionSynchronization#beforeCommit(boolean readOnly)

                     (3). 觸發事務完成前的 處理方法。

                                 AbstractPlatformTransactionManager#triggerBeforeCompletion(DefaultTransactionStatus status)

                                       TransactionSynchronizationUtils.triggerBeforeCompletion()
                                              TransactionSynchronization#beforeCompletion()

                     (4). 如果 事務有儲存點資訊,則釋放事務儲存點資訊。底層由資料庫驅動支援。

                     (5). 如果是新開啟的事務,則提交事務。底層由資料庫驅動支援。AbstractPlatformTransactionManager#doCommit(DefaultTransactionStatus status)

                     (6). 如果事務提交出現 TransactionException , RuntimeException , Error 異常 則回滾事務。呼叫事務回滾邏輯,或者設定事務回滾標記。                           

                             AbstractPlatformTransactionManager#doRollbackOnCommitException(DefaultTransactionStatus status, Throwable ex)

                     (7). 觸發事務提交後 處理方法。

                                 AbstractPlatformTransactionManager#triggerAfterCommit(DefaultTransactionStatus status)

                                      TransactionSynchronizationUtils.triggerAfterCommit()
                                            TransactionSynchronization#afterCommit()

                     (8). 觸發事務提交完成後 處理方法。

                                AbstractPlatformTransactionManager#triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus)
                                      TransactionSynchronizationManager.clearSynchronization();
                                      TransactionSynchronizationUtils.invokeAfterCompletion(synchronizations, completionStatus)
                                             TransactionSynchronization#afterCompletion(int status)

                     (9). 清理事務完成後  事務狀態(status)  資訊。AbstractPlatformTransactionManager#cleanupAfterCompletion(DefaultTransactionStatus status)

                     

 事務的隔離級別 (isolation)

隔離級別 含義
ISOLATION_DEFAULT 使用後端資料庫預設的隔離級別
ISOLATION_READ_UNCOMMITTED 最低的隔離級別,允許讀取尚未提交的資料變更,可能會導致髒讀、幻讀或不可重複讀
ISOLATION_READ_COMMITTED 允許讀取併發事務已經提交的資料,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生
ISOLATION_REPEATABLE_READ 對同一欄位的多次讀取結果都是一致的,除非資料是被本身事務自己所修改,可以阻止髒讀和不可重複讀,但幻讀仍有可能發生
ISOLATION_SERIALIZABLE 最高的隔離級別,完全服從ACID的隔離級別,確保阻止髒讀、不可重複讀以及幻讀,也是最慢的事務隔離級別,因為它通常是通過完全鎖定事務相關的資料庫表來實現的

 併發事務引起的問題 
在典型的應用程式中,多個事務併發執行,經常會操作相同的資料來完成各自的任務。併發雖然是必須的,但可能會導致一下的問題。

  • 髒讀(Dirty reads)——髒讀發生在一個事務讀取了另一個事務改寫但尚未提交的資料時。如果改寫在稍後被回滾了,那麼第一個事務獲取的資料就是無效的。
  • 不可重複讀(Nonrepeatable read)——不可重複讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的資料時。這通常是因為另一個併發事務在兩次查詢期間進行了更新。
  • 幻讀(Phantom read)——幻讀與不可重複讀類似。它發生在一個事務(T1)讀取了幾行資料,接著另一個併發事務(T2)插入了一些資料時。在隨後的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄。

 

 

事務的傳播行為(propagation behavior)

傳播行為 含義
PROPAGATION_REQUIRED 表示當前方法必須執行在事務中。如果當前事務存在,方法將會在該事務中執行。否則,會啟動一個新的事務
PROPAGATION_SUPPORTS 表示當前方法不需要事務上下文,但是如果當前上下文已存在事務的話,那麼該方法會在這個事務中執行
PROPAGATION_MANDATORY 表示該方法必須在已存在的事務中執行,如果當前事務不存在,則會丟擲一個異常
PROPAGATION_REQUIRED_NEW 表示當前方法必須執行在它自己的事務中。一個新的事務將被啟動。如果存在當前事務,在該方法執行期間,當前事務會被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager
PROPAGATION_NOT_SUPPORTED 表示該方法不應該執行在事務中。如果存在當前事務,在該方法執行期間,當前事務將被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager
PROPAGATION_NEVER 表示當前方法不應該執行在事務上下文中。如果當前正有一個事務在執行,則會丟擲異常
PROPAGATION_NESTED 表示如果當前已經存在一個事務,那麼該方法將會在巢狀事務中執行。巢狀的事務可以設定儲存點,獨立於當前事務進行單獨地提交或回滾。如果當前事務不存在,那麼其行為與PROPAGATION_REQUIRED一樣。注意各廠商對這種傳播行為的支援是有所差異的。可以參考資源管理器的文件來確認它們是否支援巢狀事務