• spring事务


    事务介绍

    事务:一组只能同时成功或失败的执行命令。
    事务特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
    隔离级别:

    • READ UNCOMMITTED (读未提交)SELECT语句以非锁定方式执行,但可能使用行的早期版本。因此,使用这个隔离级别,这样的读取是不一致的。这也叫脏读。
    • READ COMMITTED(读已提交)即使在同一事务中,每个一致的读取都将设置并读取其自己的新快照。
    • REPEATABLE READ (可重复读)这是InnoDB得默认隔离级别。 同一事务中的一致读取将读取第一次读取建立的 快照。这意味着,如果您SELECT 在“同一事务”中发出多个普通(非锁定)语句,则这些 SELECT语句彼此之间也是一致的。
    • SERIALIZABLE (序列化)此级别类似于REPEATABLE READ,但如果禁用了自动提交,则InnoDB会将所有普通的SELECT语句隐式转换为SELECT ... FOR SHARE。 如果启用了自动提交,则SELECT是它自己的事务。 因此,它被认为是只读的,并且如果以一致的(非锁定)读取方式执行并且不需要阻塞其他事务就可以序列化。 (如果其他事务已修改选定的行,则强制普通SELECT阻止,请禁用自动提交。)
    spring事务

    spring事务是通过AOP代理启用此支持,并且事务建议由元数据(当前基于XML或基于注释)驱动。 AOP与事务性元数据(即被aop增强的事物)的组合产生了一个AOP代理,该代理将TransactionInterceptor(事务拦截器)与适当的TransactionManager(事务管理器)实现结合使用,以驱动方法调用周围的事务。

    Spring的TransactionInterceptor为命令式和反应式编程模型提供事务管理。 拦截器通过检查方法返回类型来检测所需的事务管理风格。 返回反应性类型(例如Publisher或Kotlin Flow(或其子类型))的方法符合反应式事务管理的条件。 所有其他返回类型(包括void)都将代码路径用于命令式事务管理。

    同时不同的事务管理风格需要不同的事务管理器,命令式事务需要PlatformTransactionManager,而反应式事务则使用ReactiveTransactionManager实现,TransactionManager在不同的环境中有不同的实现,如PlatformTransactionManager(纯jdbc)、JtaTransactionManager(JTA)、HibernateTransactionManager(Hibernate)等。

    spring事务执行流程

    TransactionDefinition接口指定:

    • 传播行为:通常,事务范围内的所有代码都在该事务中运行。但是,如果在已存在事务上下文的情况下运行事务方法,则可以指定行为。例如,代码可以在现有事务中继续运行(常见情况),或者可以暂停现有事务并创建新事务。 Spring提供了EJB CMT熟悉的所有事务传播选项。要了解有关Spring中事务传播的语义的信息,请参阅事务传播。

    • 隔离级别:此事务与其他事务的工作隔离的程度。例如,该交易能否看到其他交易的未提交写入?

    • 超时回滚:超时之前该事务运行了多长时间,并被基础事务基础结构自动回滚。

    • 只读状态:当代码读取但不修改数据时,可以使用只读事务。在某些情况下,例如使用Hibernate时,只读事务可能是有用的优化。

    • 回滚规则:指定哪些异常(和可抛出对象)应引起自动回滚。

    <tx:advice />标记指定的各种事务设置。 默认的<tx:advice />设置为:

    • 传播行为 REQUIRED。
    • 隔离级别 DEFAULT。
    • 事务只读状态 false(读写)。
    • 事务超时 默认为基础事务系统的默认超时,如果不支持超时,则默认为无。
    • 回滚规则 任何RuntimeException都会触发回滚,而任何checkedException都不会触发。
    Attribute Required Default Description
    name Yes 与事务属性关联的方法名称。 通配符(*)可用于将相同的事务属性设置与多种方法相关联(例如,get *,handle *,on * Event等)。
    propagation No REQUIRED 事务传播行为。
    isolation No DEFAULT 事务隔离级别。 仅适用于传播设置REQUIRED或REQUIRES_NEW。
    timeout No -1 事务超时(秒)。 仅适用于REQUIRED或REQUIRES_NEW传播。
    read-only No false 读写与只读事务。 仅适用于REQUIRED或REQUIRES_NEW。
    rollback-for No 逗号分隔的触发回滚的Exception实例列表。 例如,com.foo.MyBusinessException,ServletException。
    no-rollback-for No 不触发回滚的Exception实例的逗号分隔列表。 例如,com.foo.MyBusinessException,ServletException。

    事务传播行为(org.springframework.transaction.annotation.Propagation):

    • REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED) 支持当前事务,如果不存在则创建新事务。*类似于同名的EJB事务属性。默认设置。
    • SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS) 支持当前事务,如果不存在,则以非事务方式执行。
    • MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY) 支持当前事务,如果不存在则抛出异常。
    • REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW) 创建新事务,如果当前事务存在,则挂起当前事务。尤其适用于JtaTransactionManager
    • NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED) 以非事务方式执行,如果存在当前事务,则挂起当前事务。尤其适用于JtaTransactionManager。
    • NEVER(TransactionDefinition.PROPAGATION_NEVER) 以非事务方式执行,如果存在事务,则引发异常。
    • NESTED(TransactionDefinition.PROPAGATION_NESTED) 如果当前事务存在,则在嵌套事务中执行,否则的行为类似于REQUIRED。
    xml配置方式

    基础工程 https://www.cnblogs.com/jinit/p/13912571.html
    application.xml

    <?xml version="1.0" encoding="GBK"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                                http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                                http://www.springframework.org/schema/tx
                                https://www.springframework.org/schema/tx/spring-tx.xsd
                                http://www.springframework.org/schema/aop
                                https://www.springframework.org/schema/aop/spring-aop.xsd
                                http://www.springframework.org/schema/context
                                http://www.springframework.org/schema/context/spring-context-4.1.xsd">
    
        <!--组件扫描-->
        <context:component-scan base-package="tx.*"/>
        <context:property-placeholder location="classpath:jdbc-config.properties" ignore-unresolvable="true"/>
        <!--详细配置参数见 com.alibaba.druid.pool.DruidAbstractDataSource-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
            <property name="initialSize" value="1"/>
            <property name="minIdle" value="1"/>
            <property name="maxActive" value="20"/>
            <property name="maxWait" value="60000"/>
            <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        </bean>
        <!--配置sqlSessionFactoryBean对象-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"></property>
            <!--mybatis核心配置文件-->
            <property name="configLocation" value="classpath:mybatis.xml"/>
        </bean>
        <!--配置事务管理器-->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <!--配置aop通知-->
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <!-- the transactional semantics... -->
            <tx:attributes>
                <tx:method name="get*" read-only="true"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>
        <!--aop编程配置,配置切入点(即对该方法进行增强),任意类型返回值 tx包下,OrderService的所有方法-->
        <!--<aop:config>
            <aop:pointcut id="orderServiceOperation" expression="execution(* tx.OrderService.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="orderServiceOperation"/>
        </aop:config>-->
        <!--配置Mapper对象-->
        <bean class="org.mybatis.spring.mapper.MapperFactoryBean" scope="singleton">
            <property name="mapperInterface" value="tx.mapper.AccountMapper"/>
            <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperFactoryBean" scope="singleton">
            <property name="mapperInterface" value="tx.mapper.OrderMapper"/>
            <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperFactoryBean" scope="singleton">
            <property name="mapperInterface" value="tx.mapper.StorageMapper"/>
            <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
    
        <!--注册OrderService bean-->
        <bean id="orderService" class="tx.OrderService"/>
    </beans>
    

    OrderService.java

    package tx;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import tx.entity.*;
    import tx.mapper.*;
    /**
     * @author :jty
     * @date :20-10-30
     */
    public class OrderService {
        @Autowired
        OrderMapper orderMapper;
        @Autowired
        StorageMapper storageMapper;
        @Autowired
        AccountMapper accountMapper;
       //去掉注释使用xml
       // @Transactional(rollbackFor = Exception.class)
        public void doOrder(){
            //bz0001库存减20
            storageMapper.update(new Storage(null,"bz0001",100-20,100));
            //增加20份订单
            orderMapper.add(
                    new Order(null,0001,"bz0001",20,20*100));
            //手动制造一个异常,观察数据库变化
            int m=1/0;
    
            accountMapper.update(new Account(null,0001,2000-20*100));
        }
    }
    
    
    • 库存减少storageMapper.update(new Storage(null,"bz0001",100-20,100));

    • 订单增加orderMapper.add(new Order(null,0001,"bz0001",20,20*100));

    • 账户金额不变accountMapper.update(new Account(null,0001,2000-20*100));,被异常中断

    • 将aop配置注释放开后观察到数据库不发生改变(重置数据库后执行代码)

     <!--<aop:config>
            <aop:pointcut id="orderServiceOperation" expression="execution(* tx.OrderService.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="orderServiceOperation"/>
        </aop:config>-->
    
    为不同的bean配置不同的事务
    <?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:aop="http://www.springframework.org/schema/aop"
        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.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!-- 配置不同的切入点 -->
        <aop:config>
    
            <aop:pointcut id="defaultServiceOperation"
                    expression="execution(* x.y.service.*Service.*(..))"/>
    
            <aop:pointcut id="noTxServiceOperation"
                    expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>
    
            <aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
    
            <aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>
    
        </aop:config>
    
        <!-- this bean will be transactional (see the 'defaultServiceOperation' pointcut) -->
        <bean id="fooService" class="x.y.service.DefaultFooService"/>
    
        <!-- this bean will also be transactional, but with totally different transactional settings -->
        <bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/>
    
        <!-- 不同的通知 -->
        <tx:advice id="defaultTxAdvice">
            <tx:attributes>
                <tx:method name="get*" read-only="true"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>
    
        <tx:advice id="noTxAdvice">
            <tx:attributes>
                <tx:method name="*" propagation="NEVER"/>
            </tx:attributes>
        </tx:advice>
    
        <!-- 其他配置同单个(上述) -->
    
    </beans>
    
    使用@Transactional

    注释在上面的类级别使用,注释指示声明类(及其子类)的所有方法的默认值。 另外,每种方法都可以单独注释。 请注意,类级别的注释不适用于类层次结构中的祖先类。 在这种情况下,需要在本地重新声明方法,以参与子类级别的注释。

    • 应仅将@Transactional注释应用于具有公共可见性的方法。如果使用注释对受保护的,私有的或程序包可见的方法进行@Transactional注释,则不会引发任何错误,但是带注释的方法不会显示已配置的事务设置。
    • 建议使用@Transactional注释仅注释具体的类(以及具体类的方法),而不是注释接口。 您当然可以在接口(或接口方法)上放置@Transactional批注,但这仅在您使用基于接口的代理时才可以正常使用。 Java注释不是从接口继承的事实意味着,如果您使用基于类的代理(proxy-target-class="true")或基于编织的方面(mode="aspectj"),则事务设置不会 由代理和编织基础结构识别,并且该对象未包装在事务代理中。
      application.xml
    <?xml version="1.0" encoding="GBK"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                                http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                                http://www.springframework.org/schema/tx
                                https://www.springframework.org/schema/tx/spring-tx.xsd
                                http://www.springframework.org/schema/aop
                                https://www.springframework.org/schema/aop/spring-aop.xsd
                                http://www.springframework.org/schema/context
                                http://www.springframework.org/schema/context/spring-context-4.1.xsd">
    
        <!--组件扫描-->
        <context:component-scan base-package="tx.*"/>
        <context:property-placeholder location="classpath:jdbc-config.properties" ignore-unresolvable="true"/>
        <!--详细配置参数见 com.alibaba.druid.pool.DruidAbstractDataSource-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
            <property name="initialSize" value="1"/>
            <property name="minIdle" value="1"/>
            <property name="maxActive" value="20"/>
            <property name="maxWait" value="60000"/>
            <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        </bean>
        <!--配置sqlSessionFactoryBean对象-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"></property>
            <!--mybatis核心配置文件-->
            <property name="configLocation" value="classpath:mybatis.xml"/>
        </bean>
        <!--配置事务管理器-->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <!-- enable the configuration of transactional behavior based on annotations 开启事务注解-->
        <!-- 去掉tx:advice和aop:config配置,通过@Transactional注解定义事务和定位aop代理目标-->
        <tx:annotation-driven transaction-manager="txManager"/><!-- a TransactionManager is still required -->
        <!--注释掉tx:advice和aop:config-->
        <!--配置aop通知-->
        <!--<tx:advice id="txAdvice" transaction-manager="txManager">
            &lt;!&ndash; the transactional semantics... &ndash;&gt;
            <tx:attributes>
                &lt;!&ndash;get方法事务只读&ndash;&gt;
                <tx:method name="get*" read-only="true" isolation="DEFAULT" timeout="-1" rollback-for="RuntimeException" propagation="REQUIRED" no-rollback-for="ArithmeticException"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>-->
        <!--aop编程配置,配置切入点(即对该方法进行增强),任意类型返回值 tx包下,OrderService的所有方法-->
       <!-- <aop:config>
            <aop:pointcut id="orderServiceOperation" expression="execution(* tx.OrderService.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="orderServiceOperation"/>
        </aop:config>-->
        <!--配置Mapper对象-->
        <bean class="org.mybatis.spring.mapper.MapperFactoryBean" scope="singleton">
            <property name="mapperInterface" value="tx.mapper.AccountMapper"/>
            <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperFactoryBean" scope="singleton">
            <property name="mapperInterface" value="tx.mapper.OrderMapper"/>
            <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperFactoryBean" scope="singleton">
            <property name="mapperInterface" value="tx.mapper.StorageMapper"/>
            <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
    
        <!--注册OrderService bean-->
        <bean id="orderService" class="tx.OrderService"/>
    </beans>
    

    OrderService.java

    public class OrderService {
        @Autowired
        OrderMapper orderMapper;
        @Autowired
        StorageMapper storageMapper;
        @Autowired
        AccountMapper accountMapper;
    
       @Transactional(rollbackFor = Exception.class,propagation= Propagation.REQUIRED,isolation= Isolation.DEFAULT,timeout = -1)
        public void doOrder(){
            //bz0001库存减20
            storageMapper.update(new Storage(null,"bz0001",100-20,100));
            //增加20份订单
            orderMapper.add(
                    new Order(null,0001,"bz0001",20,20*100));
            //手动制造一个异常,观察数据库变化
            int m=1/0;
    
            accountMapper.update(new Account(null,0001,1500-20*100));
        }
    }
    
    原理
       <!--注册OrderService bean-->
        <bean id="orderService" class="tx.OrderService"/>
    
      <tx:advice id="txAdvice" transaction-manager="txManager">
            <!-- the transactional semantics... -->
            <tx:attributes>
                <!--get方法事务只读-->
                <tx:method name="get*" read-only="true" isolation="DEFAULT" timeout="-1" rollback-for="RuntimeException" propagation="REQUIRED" no-rollback-for="ArithmeticException"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>
      <aop:config>
            <aop:pointcut id="orderServiceOperation" expression="execution(* tx.OrderService.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="orderServiceOperation"/>
        </aop:config>
    
    • 通过tx:advice标签可知道该标签配置的对象为org.springframework.transaction.interceptor.TransactionInterceptor
    • 通过aop:config标签可知道spring通过txAdvice对象的invoke(MethodInvocation invocation)方法代理orderServiceOperation对象
    • 即通过该方法org.springframework.transaction.interceptor.TransactionInterceptor#invoke代理我们定义的切入点
    //方法调用的描述,在方法调用时提供给拦截器。即在调用切入掉表达式式定义的方式时,将被拦截获得该对象MethodInvocation
    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);
    
    		 // Adapt to TransactionAspectSupport's invokeWithinTransaction...
                     //invocation.getMethod():tx.OrderService.doOrder(),被代理的方法;invocation::proceed:invocation的proceed方法作为参数,
                     //‘::’方法引用,接受该方法的接口
        /*@FunctionalInterface
        protected interface InvocationCallback {
    
        Object proceedWithInvocation() throws Throwable;
        }*/
                     //即InvocationCallback.proceedWithInvocation()相当于invocation.proceed();
                     //旧版本代码如下
        /* return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
        @Override
        public Object proceedWithInvocation() throws Throwable {
            return invocation.proceed();
        }
        });*/
    		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    	}
    

    TransactionAspectSupport.invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation)

    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
    			final InvocationCallback invocation) throws Throwable {
    
    		// If the transaction attribute is null, the method is non-transactional.
                    //获取 <tx:attributes>中的配置
    		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);
                    //获取连接点 tx.OrderService.doOrder
    		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    
    		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
    			// Standard transaction demarcation with getTransaction and commit/rollback calls.
                            //使用getTransaction和commit / rollback调用进行标准事务划分。
                            //获取事务信息 包括事务管理器、连接点、事务定义参数、事务状态等
    			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
    
    			Object retVal;
    			try {
    				// This is an around advice: Invoke the next interceptor in the chain.
    				// This will normally result in a target object being invoked.
                                     //环绕通知,调用目标连接点方法
    				retVal = invocation.proceedWithInvocation();
    			}
    			catch (Throwable ex) {
    				// target invocation exception
                                    //若目标方法调用出现异常,根据异常类型对本次事务进行提交或者回滚。
    				completeTransactionAfterThrowing(txInfo, ex);
    				throw ex;
    			}
    			finally {
                                    //重置 本线程事务信息 
    				cleanupTransactionInfo(txInfo);
    			}
    
    			if (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 {
    			final ThrowableHolder throwableHolder = new ThrowableHolder();
    
    			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
    			try {
    				Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
    					TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
    					try {
    						Object retVal = invocation.proceedWithInvocation();
    						if (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);
    					}
    				});
    
    				// Check result state: It might indicate a Throwable to rethrow.
    				if (throwableHolder.throwable != null) {
    					throw throwableHolder.throwable;
    				}
    				return result;
    			}
    			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;
    			}
    		}
    	}
    
    
  • 相关阅读:
    数值的整数次方
    Grid Sorting
    第K小的数
    图形学变换矩阵的分解
    神经网络理论简介(三)
    神经网络理论简介(二)
    神经网络理论简介(一)
    C/C++的内存对齐
    strcpy的实现
    C++对象模型简析
  • 原文地址:https://www.cnblogs.com/jinit/p/13917482.html
Copyright © 2020-2023  润新知