事务配置

<?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.TransactionAttributeSourcePointcut#matches(Method method, Class<?> targetClass)进行是否需要注入事务拦截器判断。事务切入点只处理 public 修饰的方法。org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) 

            最终获得的事务默认拦截器是 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一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务

 

事务失效场景

1. 方法不是 public 修饰的。在AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有个判断,如果目标方法不是 public,则TransactionAttribute返回 null,即不支持事务。

2. 方法通过 final 修饰。无法重写,则无法添加事务支持。

3. 方法调用当前类的其他方法。

        解决方法一: 在该 Service 类中注入自己。然后通过注入的代理对象调用方法。

@Servcie
public class ServiceA {
   @Autowired
   prvate ServiceA serviceA;
 
   @Transactional(rollbackFor=Exception.class)
   public void save(User user) {
         queryData1();
         queryData2();
         serviceA.save2(user);
   }
 
   @Transactional(rollbackFor=Exception.class)
   public void save2(User user) {
       addData1();
       updateData2();
    }
 }
View Code

       解决方法二: AOP代理开启配置,使用 AopContext.currentProxy() 获取代理对象,再去调用对应方法。

<aop:aspectj-autoproxy expose-proxy=“true”> 设置expose-proxy属性为true,将代理暴露出来,使用AopContext.currentProxy()获取当前代理

@Servcie
public class ServiceA {

   @Transactional(rollbackFor=Exception.class)
   public void save(User user) {
         queryData1();
         queryData2();
         ((ServiceA)AopContext.currentProxy()).save2(user);
   }
 
   @Transactional(rollbackFor=Exception.class)
   public void save2(User user) {
       addData1();
       updateData2();
    }
 }
View Code

4. 没有使用 Spring 管理 bean 对象,无法生成事务代理。

5. 多线程调用,无法进行事务管理。

    在特殊情况下,需要多线程优化,可以使用编程事务,模拟伪两阶段提交(2PC)实行。但主要两阶段提交缺陷,给手动修改数据留好日志。

public class MainTest {
    //是否可以提交
    public static volatile boolean IS_OK = true;

    public static void main(String[] args) {
        //子线程等待主线程通知
        CountDownLatch mainMonitor = new CountDownLatch(1);
        int threadCount = 5;
        CountDownLatch childMonitor = new CountDownLatch(threadCount);
        //子线程运行结果
        List<Boolean> childResponse = new ArrayList<Boolean>();
        ExecutorService executor = Executors.newCachedThreadPool();
        for (int i = 0; i < threadCount; i++) {
            int finalI = i;
            executor.execute(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + ":开始执行");
// if (finalI == 4) {
// throw new Exception("出现异常");
// }
                    TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(1000));
                    childResponse.add(Boolean.TRUE);
                    childMonitor.countDown();
                    System.out.println(Thread.currentThread().getName() + ":准备就绪,等待其他线程结果,判断是否事务提交");
                    mainMonitor.await();
                    if (IS_OK) {
                        System.out.println(Thread.currentThread().getName() + ":事务提交");
                    } else {
                        System.out.println(Thread.currentThread().getName() + ":事务回滚");
                    }
                } catch (Exception e) {
                    childResponse.add(Boolean.FALSE);
                    childMonitor.countDown();
                    System.out.println(Thread.currentThread().getName() + ":出现异常,开始事务回滚");
                }
            });
        }
        //主线程等待所有子线程执行response
        try {
            childMonitor.await();
            for (Boolean resp : childResponse) {
                if (!resp) {
                    //如果有一个子线程执行失败了,则改变mainResult,让所有子线程回滚
                    System.out.println(Thread.currentThread().getName()+":有线程执行失败,标志位设置为false");
                    IS_OK = false;
                    break;
                }
            }
            //主线程获取结果成功,让子线程开始根据主线程的结果执行(提交或回滚)
            mainMonitor.countDown();
            //为了让主线程阻塞,让子线程执行。
            Thread.currentThread().join();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
View Code

6. 数据库表不支持事务。

 

事务不回滚

1. 事务传播特性设置错误。

2. 自己捕获异常处理后,没有继续抛出异常。导致事务拦截器没有捕获到异常,无法回滚。

3. 手动抛出的异常不在配置或默认的回归异常范围内。

4. 嵌套事务回滚多了。 嵌套事务回滚后,部分事务管理器回继续抛出异常,这是先捕获内部事务异常,然后再做其他处理。

@Service
public class UserService {
 
    @Autowired
    private UserMapper userMapper;
 
    @Autowired
    private RoleService roleService;
 
    @Transactional
    public void add(UserModel userModel) throws Exception {
 
        userMapper.insertUser(userModel);
        try {
            roleService.doOtherThing();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}
View Code

 

当遇到复杂情况,须手动控制事务时,可以用编程式事务精确控制。

 @Autowired
   private TransactionTemplate transactionTemplate;
   
   public void save(final User user) {
         queryData1();
         queryData2();
         transactionTemplate.execute((status) => {
            addData1();
            updateData2();
            return Boolean.TRUE;
         })
View Code

 

posted on 2022-03-24 22:14  流羽  阅读(68)  评论(0编辑  收藏  举报