• Spring 事务源码


      Spring 的源码一般从@EnableXX 开始看,然后会导入@Enable 一般通过@Import 导入一些相关的配置类。

    0. 前沿

    ACID Atomicity Consistency Isolation Durabiliry

    - 原子性 事务要么全做要么不做
    - 一致性 事务前后的状态是一致的,不会造成数据不一致的状态
    - 隔离性 多个事务直接互相不影响
    - 永久性 一个事务commit 之后对数据的影响是永久性的

    脏读: 事务A读取到事务B未提交的数据

    不可重复度: 事务A两次读取同一条数据内容不一致,也就是读到了其他事务修改掉的数据

    幻读/虚读: 两次读取到的数据量不一致

    关于隔离级别与事务问题对应关系如下:

       对于Mysql 来说,RR 隔离级别也不存在虚读的问题,也就是Mysql 事务读取不到其他事务新增加的数据。 采用多版本并发控制(MVCC)机制解决幻读问题 。

    测试:

    表结构:

    CREATE TABLE `account` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `accountName` varchar(20) DEFAULT NULL,
      `user` varchar(20) DEFAULT NULL,
      `money` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

    1. 脏读问题测试:

    (1) session1:

    SET tx_isolation = 'read-uncommitted';
    
    BEGIN;
    
    INSERT INTO account(accountName, USER, money) VALUES('zs', 'zs', 100)
    
    ROLLBACK;
    
    COMMIT;

    (2) session2

    SET tx_isolation = 'read-uncommitted';
    
    SELECT * FROM account;

    结果: session2 会读到未提交的数据

    2. 不可重复读: 两次读到的数据内容不一致

    插入一条数据:

     (1) session1 执行如下:

    SET tx_isolation = 'read-committed';
    
    BEGIN;
    
    select * from account;
    
    # 做其他操作
    select * from account;
    
    COMMIT;

    (2) session2 如下:

    SET tx_isolation = 'read-committed';
    
    BEGIN;
    
    update account set money = money + 1;
    
    COMMIT;

    测试:

    • session1 先执行第一次select,结果如下:

    •  session2 进行update:
    • session1 第二次进行select, 结果如下: (一次事务多次读取数据内容不一致)

     3. 幻读: 同一个事务两次读到的数据量不一致

    (1) session1

    SET tx_isolation = 'repeatable-read';
    
    BEGIN;
    
    select * from account;
    
    # 另外一条事务插入数据
    
    select * from account;
    
    insert into account(accountName, user, money) values('zs', 'zs', 100)
    
    select * from account;
    
    update account set money = money + 1 where user = 'zs';
    
    select * from account;
    
    update account set money = money + 1 where user = 'wangwu';
    
    select * from account;
    
    COMMIT;

    (2) session2:

    SET tx_isolation = 'repeatable-read';
    
    BEGIN;
    
    insert into account(accountName, user, money) values('wangwu', 'wangwu', 100);
    
    commit;

    测试:

    (1) 确保数据库只有一条数据: 新开事务插入一条数据

    truncate table account; 
    insert into account(accountName, user, money) values('lisi', 'lisi', 100);
    select * from account;

     (2) 执行session1 第一次查询语句之前的开启事务以及查询语句:

     (3) 执行session2 的insert 操作,并且提交

    (4) 新事务查询

     (5) 执行session1 第二次查询语句:

     (6) 执行session1 的insert 操作

    (7) 再次执行session1 的第三次查询

    (8) 执行session1 的修改操作

    (9) 再次执行session1 的查询操作

    (10) 执行session1 的第二次 修改

    (11) 最后再次查询, 发现数据多出来一条

     可以看出,update 是采用的当前读,虽然当前事务没有查到相关数据,但是update 也会成功,并且update 之后会将update 的数据加入当前事务。

    1. 配置类解读

    事务的入口: org.springframework.transaction.annotation.EnableTransactionManagement

    package org.springframework.transaction.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.context.annotation.AdviceMode;
    import org.springframework.context.annotation.Import;
    import org.springframework.core.Ordered;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(TransactionManagementConfigurationSelector.class)
    public @interface EnableTransactionManagement {
        boolean proxyTargetClass() default false;
    
        AdviceMode mode() default AdviceMode.PROXY;

    int order() default Ordered.LOWEST_PRECEDENCE; }

    通过@Import 引入了TransactionManagementConfigurationSelector

    package org.springframework.transaction.annotation;
    
    import org.springframework.context.annotation.AdviceMode;
    import org.springframework.context.annotation.AdviceModeImportSelector;
    import org.springframework.context.annotation.AutoProxyRegistrar;
    import org.springframework.transaction.config.TransactionManagementConfigUtils;
    import org.springframework.util.ClassUtils;

    public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {determineTransactionAspectClass()}; default: return null; } } private String determineTransactionAspectClass() { return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ? TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME : TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME); } }

    这里会注入ProxyTransactionManagementConfiguration,自动配置类:org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration, 这个类注入了几个重要的事务相关bean

    package org.springframework.transaction.annotation;
    
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Role;
    import org.springframework.transaction.config.TransactionManagementConfigUtils;
    import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
    import org.springframework.transaction.interceptor.TransactionAttributeSource;
    import org.springframework.transaction.interceptor.TransactionInterceptor;
    
    @Configuration(proxyBeanMethods = false)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
    
        @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
                TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
    
            BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
            advisor.setTransactionAttributeSource(transactionAttributeSource);
            advisor.setAdvice(transactionInterceptor);
            if (this.enableTx != null) {
                advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
            }
            return advisor;
        }
    
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public TransactionAttributeSource transactionAttributeSource() {
            return new AnnotationTransactionAttributeSource();
        }
    
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
            TransactionInterceptor interceptor = new TransactionInterceptor();
            interceptor.setTransactionAttributeSource(transactionAttributeSource);
            if (this.txManager != null) {
                interceptor.setTransactionManager(this.txManager);
            }
            return interceptor;
        }
    
    }

    (1) org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration 事务自动配置的相关类

    (2) org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor 可以理解为切面Aspect的角色(内部维护Point与Advisor)

    (3) org.springframework.transaction.interceptor.TransactionAttributeSource 用于获取TransactionAttribute 事务属性,也就是读取@Transactional 注解上的相关属性

    (4) org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#TransactionAttributeSourcePointcut (是否需要进行事务的控制是在这个类进行判断的)

    (5) org.springframework.transaction.interceptor.TransactionInterceptor 事务拦截器。 (对事务的处理是在这个类)

    2. 分析过程

    事务的拦截器入口: org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor, 源码如下:

    package org.springframework.transaction.interceptor;
    
    import org.springframework.aop.ClassFilter;
    import org.springframework.aop.Pointcut;
    import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor;
    import org.springframework.lang.Nullable;
    @SuppressWarnings("serial")
    public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    
        @Nullable
        private TransactionAttributeSource transactionAttributeSource;
    
        private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
            @Override
            @Nullable
            protected TransactionAttributeSource getTransactionAttributeSource() {
                return transactionAttributeSource;
            }
        };
    
        public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
            this.transactionAttributeSource = transactionAttributeSource;
        }
    
        public void setClassFilter(ClassFilter classFilter) {
            this.pointcut.setClassFilter(classFilter);
        }
    
        @Override
        public Pointcut getPointcut() {
            return this.pointcut;
        }
    
    }

    TransactionAttributeSource:上面配置类设置的 org.springframework.transaction.annotation.AnnotationTransactionAttributeSource, 用于获取TransactionAttribute 事务属性,也就是读取@Transactional 注解上的相关属性

    pointcut 切入点: org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#TransactionAttributeSourcePointcut (是否需要进行事务的控制是在这个类进行判断的)

    advice 通知:  org.springframework.transaction.interceptor.TransactionInterceptor 事务拦截器。 (对事务的处理是在这个类)

    3.  事务属性TransactionAttribute解析构造过程

    0. 事务测试类:

    package com.xm.ggn.test;
    
    import com.xm.ggn.bean.common.Message;
    import com.xm.ggn.mapper.common.MessageMapper;
    import org.springframework.aop.framework.AopContext;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Service;
    
    import javax.transaction.Transactional;
    import java.sql.SQLException;
    
    @Service
    // Primary可以理解为默认优先选择,不可以同时设置多个,内部实质是设置BeanDefinition的primary属性。
    @Primary
    //@Transactional
    public class MessageService2Impl implements MessageService2 {
    
        @Autowired
        private MessageMapper messageMapper;
    
        @Override
        @Transactional
        public void tx1() {
            // 调用tx3方法会回滚,因为这里有事务直接,会走代理,且tx3方法会加入本事务
            tx3();
        }
    
        @Override
        public void tx2() {
            // 调用tx3方法不会回滚,因为这里没有事务。即使tx3有事务也不会走代理,因为通过内部方法调用不会走代理。解决办法查看tx4 方法
            tx3();
        }
    
        @Override
        @Transactional
        public void tx3() {
            Message message = new Message();
            message.setTitle("tx3");
            messageMapper.insert(message);
    
            int i = 1 / 0;
        }
    
        //  这样进行方法内部调用AOP会生效,主启动类加@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) 注解
        @Override
        public void tx4() {
            MessageService2 messageService = (MessageService2) AopContext.currentProxy();
            // 这样调用tx3会进行回滚,走的是代理类的方法
            messageService.tx3();
        }
    
        @Override
        @Transactional(rollbackOn = Exception.class)
        public void tx5() throws SQLException {
            Message message = new Message();
            message.setTitle("tx3");
            messageMapper.insert(message);
    
            throw new SQLException("xxx");
        }
    }

    1. AOP程序入口 org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept

            @Nullable
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object oldProxy = null;
                boolean setProxyContext = false;
                Object target = null;
                TargetSource targetSource = this.advised.getTargetSource();
    
                Object var16;
                try {
                    if (this.advised.exposeProxy) {
                        oldProxy = AopContext.setCurrentProxy(proxy);
                        setProxyContext = true;
                    }
    
                    target = targetSource.getTarget();
                    Class<?> targetClass = target != null ? target.getClass() : null;
                    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                    Object retVal;
                    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                        retVal = methodProxy.invoke(target, argsToUse);
                    } else {
                        retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
                    }
    
                    retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
                    var16 = retVal;
                } finally {
                    if (target != null && !targetSource.isStatic()) {
                        targetSource.releaseTarget(target);
                    }
    
                    if (setProxyContext) {
                        AopContext.setCurrentProxy(oldProxy);
                    }
    
                }
    
                return var16;
            }

     这里的核心是 获取一个AOP调用链条, List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 所以是否需要事务控制只需要判断该chain 是否包含对应的Inteceptor。

    (1) 针对tx1() 方法进行测试:获取到的chain 如下 = 可以看到有事务拦截器。则会用AOP进行事务处理

    (2) 针对tx2() 方法进行测试: 获取到的chain 如下 = 可以看到没有事务相关的拦截器,则事务不会生效

    2. 获取方法对应的AOP链分析

     org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice 方法根据方法获取对应的AOP处理器链

        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
            AdvisedSupport.MethodCacheKey cacheKey = new AdvisedSupport.MethodCacheKey(method);
            List<Object> cached = (List)this.methodCache.get(cacheKey);
            if (cached == null) {
                cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
                this.methodCache.put(cacheKey, cached);
            }
    
            return cached;
        }

      可以看到会从缓存中拿, 如果缓存中拿不到就会调用方法org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 获取并且放到缓存map。 所以需要从org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法获取需要加载的AOP处理器链。

    1. 分析 tx1() 方法获取AOP处理器链的过程:

    最终获取的方法会打到: org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
            AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
            Advisor[] advisors = config.getAdvisors();
            List<Object> interceptorList = new ArrayList(advisors.length);
            Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass();
            Boolean hasIntroductions = null;
            Advisor[] var9 = advisors;
            int var10 = advisors.length;
    
            for(int var11 = 0; var11 < var10; ++var11) {
                Advisor advisor = var9[var11];
                if (advisor instanceof PointcutAdvisor) {
                    PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
                    if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                        MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                        boolean match;
                        if (mm instanceof IntroductionAwareMethodMatcher) {
                            if (hasIntroductions == null) {
                                hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                            }
    
                            match = ((IntroductionAwareMethodMatcher)mm).matches(method, actualClass, hasIntroductions);
                        } else {
                            match = mm.matches(method, actualClass);
                        }
    
                        if (match) {
                            MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                            if (mm.isRuntime()) {
                                MethodInterceptor[] var17 = interceptors;
                                int var18 = interceptors.length;
    
                                for(int var19 = 0; var19 < var18; ++var19) {
                                    MethodInterceptor interceptor = var17[var19];
                                    interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                                }
                            } else {
                                interceptorList.addAll(Arrays.asList(interceptors));
                            }
                        }
                    }
                } else if (advisor instanceof IntroductionAdvisor) {
                    IntroductionAdvisor ia = (IntroductionAdvisor)advisor;
                    if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                        Interceptor[] interceptors = registry.getInterceptors(advisor);
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                } else {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
    
            return interceptorList;
        }

    (1) config.getAdvisors(); 获取到所有的通知, 获取到的通知的数组如下:

    (2) 遍历上面获取的通知,然后根据方法转交给MethodMatcher判断是否需要进行AOP处理器链调用。比如对于下标为2的Advisor获取到的MethodMatcher 是:

     (3) 调用org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches 方法判断是否需要添加此AOP

        @Override
        public boolean matches(Method method, Class<?> targetClass) {
            TransactionAttributeSource tas = getTransactionAttributeSource();
            return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
        }

    -1》 这里首先获取TransactionAttributeSource, 这里获取到的就是AnnotationTransactionAttributeSource

    -2》调用方法org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute 获取方法对应的事务属性

        public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
            if (method.getDeclaringClass() == Object.class) {
                return null;
            }
    
            // First, see if we have a cached value.
            Object cacheKey = getCacheKey(method, targetClass);
            TransactionAttribute cached = this.attributeCache.get(cacheKey);
            if (cached != null) {
                // Value will either be canonical value indicating there is no transaction attribute,
                // or an actual transaction attribute.
                if (cached == NULL_TRANSACTION_ATTRIBUTE) {
                    return null;
                }
                else {
                    return cached;
                }
            }
            else {
                // We need to work it out.
                TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
                // Put it in the cache.
                if (txAttr == null) {
                    this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
                }
                else {
                    String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
                    if (txAttr instanceof DefaultTransactionAttribute) {
                        ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
                    }
                    if (logger.isTraceEnabled()) {
                        logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
                    }
                    this.attributeCache.put(cacheKey, txAttr);
                }
                return txAttr;
            }
        }
    • 这里先构造一个cacheKey, org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getCacheKey
        protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
            return new MethodClassKey(method, targetClass);
        }

    对于上面的方法tx1() 获取到的cacheKey 如下:

    •  用上面获取的cacheKey 作为key 从缓存map attributeCache 中拿取,org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache如下:
        private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);

    对于上面tx1() 方法获取到的TransactionAttribute 属性如下:可以看到默认的传播行为是PROPAGATION_REQUIRED, 默认的事务隔离级别是采用数据库的隔离级别

       然后将获取到的TransactionAttribute 属性返回去。 也就是获取到此对象就需要事务AOP,否则不需要。

    2. org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache 存数据过程

      这个缓存存数据的过程也就是解析方法对应的事务属性TransactionAttribute 的过程。

    看是什么时候存储的,只需要查看什么时候put的,发现是在方法:org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute,断点查看调用链如下:

    通过上面了解到,判断一个方法是否需要事务AOP处理是从org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache 判断的,接下来研究这个map 是什么时候存入数据的。

    (1) SpringIoC 对象创建过程中会调用org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary,

    方法内部调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean 获取Advisor[], 

    最终会调用到方法 org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches, 也就是 上面判断是否需要 进行事务AOP, 然后调用到方法org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute

        public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
            if (method.getDeclaringClass() == Object.class) {
                return null;
            }
    
            // First, see if we have a cached value.
            Object cacheKey = getCacheKey(method, targetClass);
            TransactionAttribute cached = this.attributeCache.get(cacheKey);
            if (cached != null) {
                // Value will either be canonical value indicating there is no transaction attribute,
                // or an actual transaction attribute.
                if (cached == NULL_TRANSACTION_ATTRIBUTE) {
                    return null;
                }
                else {
                    return cached;
                }
            }
            else {
                // We need to work it out.
                TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
                // Put it in the cache.
                if (txAttr == null) {
                    this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
                }
                else {
                    String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
                    if (txAttr instanceof DefaultTransactionAttribute) {
                        ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
                    }
                    if (logger.isTraceEnabled()) {
                        logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
                    }
                    this.attributeCache.put(cacheKey, txAttr);
                }
                return txAttr;
            }
        }

      根据方法和类构造一个 cacheKey 对象(实际类型是org.springframework.core.MethodClassKey, 也就是将方法和class 封装成一个对象作为key),然后刚进来获取到的cached 为null,所以会走下面的第一次计算并且获取TransactionAttribute 对象。

    (2) 接下来走 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute:

        protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
            // Don't allow no-public methods as required.
            if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
                return null;
            }
    
            // The method may be on an interface, but we need attributes from the target class.
            // If the target class is null, the method will be unchanged.
            Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
    
            // First try is the method in the target class.
            TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
            if (txAttr != null) {
                return txAttr;
            }
    
            // Second try is the transaction attribute on the target class.
            txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
            if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
                return txAttr;
            }
    
            if (specificMethod != method) {
                // Fallback is to look at the original method.
                txAttr = findTransactionAttribute(method);
                if (txAttr != null) {
                    return txAttr;
                }
                // Last fallback is the class of the original method.
                txAttr = findTransactionAttribute(method.getDeclaringClass());
                if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
                    return txAttr;
                }
            }
    
            return null;
        }

      这里的逻辑是:先从方法上获取,然后从类上获取。也就是先以方法的为准,然后以类上的为准。

    1》首先从方法上获取注解:org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)

        protected TransactionAttribute findTransactionAttribute(Method method) {
            return determineTransactionAttribute(method);
        }

    转交给方法:org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute

        protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
            for (TransactionAnnotationParser parser : this.annotationParsers) {
                TransactionAttribute attr = parser.parseTransactionAnnotation(element);
                if (attr != null) {
                    return attr;
                }
            }
            return null;
        }

    这里获取Set<TransactionAnnotationParser> annotationParsers , 然后遍历获取TransactionAttribute, annotationParsers 如下:

    可以看到这里有两个解析器。第一个是解析Spring 包下面的Transactional注解的解析器, 第二个是解析javax包下面的Transactional 注解的解析器。也就是两个注解都可以,对应两个不同的解析器。

    • org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement) 解析个过程如下:

    首先获取Spring包下面的注解:

        @Override
        @Nullable
        public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
            AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
                    element, Transactional.class, false, false);
            if (attributes != null) {
                return parseTransactionAnnotation(attributes);
            }
            else {
                return null;
            }
        }

    获取到之后调用方法parseTransactionAnnotation 解析并且封装事务属性, 获取注解的方法委托给Spring 的工具类 org.springframework.core.annotation.AnnotatedElementUtils#findMergedAnnotationAttributes(java.lang.reflect.AnnotatedElement, java.lang.Class<? extends java.lang.annotation.Annotation>, boolean, boolean), 封装TransactionAttribute 对象的过程如下:

        public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
            return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
        }
    
        protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
            RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
    
            Propagation propagation = attributes.getEnum("propagation");
            rbta.setPropagationBehavior(propagation.value());
            Isolation isolation = attributes.getEnum("isolation");
            rbta.setIsolationLevel(isolation.value());
            rbta.setTimeout(attributes.getNumber("timeout").intValue());
            rbta.setReadOnly(attributes.getBoolean("readOnly"));
            rbta.setQualifier(attributes.getString("value"));
    
            List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
            for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
                rollbackRules.add(new RollbackRuleAttribute(rbRule));
            }
            for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
                rollbackRules.add(new RollbackRuleAttribute(rbRule));
            }
            for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
                rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
            }
            for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
                rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
            }
            rbta.setRollbackRules(rollbackRules);
    
            return rbta;
        }

    org.springframework.transaction.annotation.JtaTransactionAnnotationParser事务解析器中获取到javax.transaction.Transactional 注解封装事务属性过程如下:

     org.springframework.transaction.annotation.JtaTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement) 方法如下:

        public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
            AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
                    element, javax.transaction.Transactional.class);
            if (attributes != null) {
                return parseTransactionAnnotation(attributes);
            }
            else {
                return null;
            }
        }

      首先获取方法Transactional 注解的属性并封装到AnnotationAttributes, 然后调用:调用方法org.springframework.transaction.annotation.JtaTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes) 组装成 TransactionAttribute

        protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
            RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
    
            // 获取事务的 传播特性
            rbta.setPropagationBehaviorName(
                    RuleBasedTransactionAttribute.PREFIX_PROPAGATION + attributes.getEnum("value").toString());
    
            // 建立rolebackOn 和 dontRollbackOn 特性
            List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
            for (Class<?> rbRule : attributes.getClassArray("rollbackOn")) {
                rollbackRules.add(new RollbackRuleAttribute(rbRule));
            }
            for (Class<?> rbRule : attributes.getClassArray("dontRollbackOn")) {
                rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
            }
            rbta.setRollbackRules(rollbackRules);
    
            return rbta;
        }

       将获取到的TransactionAttribute 返回给方法org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute。 然后缓存到本地的attributeCache 属性中。

     4. 事务处理过程分析

      上面研究了事务属性的解析过程,大致过程是先解析方法上是否有事务属性,也就是是否有@Transactional 注解(包含javax.transaction包和Spring包的,对应两种解析器); 如果方法没找到就从类上找,类上找的时候也会从类继承的接口上找,所以事务注解具有了继承性。找到之后存到org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache缓存Map中;如果没找到也存一个默认的空对象进去,Map的key是类和方法组成的一个对象。 此缓存Map 用于之后判断某个方法在AOP调用链获取过程中判断是否需要进行事务通知的处理。接下来研究事务通知的处理过程。

     1. 事务通知入口:

    org.springframework.transaction.interceptor.TransactionInterceptor#invoke (该方法继承自org.aopalliance.intercept.MethodInterceptor#invoke)

        @Override
        @Nullable
        public Object invoke(MethodInvocation invocation) throws Throwable {
            // Work out the target class: may be {@code null}.
            // The TransactionAttributeSource should be passed the target class
            // as well as the method, which may be from an interface.
            Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    
            // Adapt to TransactionAspectSupport's invokeWithinTransaction...
            return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
        }

     2. 然后请求转交给父类org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

        @Nullable
        protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
                final InvocationCallback invocation) throws Throwable {
    
            // If the transaction attribute is null, the method is non-transactional.
            TransactionAttributeSource tas = getTransactionAttributeSource();
            final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
            final TransactionManager tm = determineTransactionManager(txAttr);
    
            if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
                ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
                    if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
                        throw new TransactionUsageException(
                                "Unsupported annotated transaction on suspending function detected: " + method +
                                ". Use TransactionalOperator.transactional extensions instead.");
                    }
                    ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
                    if (adapter == null) {
                        throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
                                method.getReturnType());
                    }
                    return new ReactiveTransactionSupport(adapter);
                });
                return txSupport.invokeWithinTransaction(
                        method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
            }
    
            PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
            final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    
            if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
                // Standard transaction demarcation with getTransaction and commit/rollback calls.
                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;
                }
            }
        }

    所以事务的核心逻辑代码是在这个方法内部,下面着重分析这个方法的代码逻辑。    也可以看到这里使用的是一个环绕通知

    测试:

    $ curl http://localhost:8088/tx1
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100    78    0    78    0     0      6      0 --:--:--  0:00:12 --:--:--    21{"success":false,"data":null,"msg":"系统内部错误","errorCode":"u200000"}

    主要做的事情如下:

    (1)  获取TransactionAttribute 对象, 获取到的对象如下:

    tas.getTransactionAttribute(method, targetClass) 获取事务属性, 实际最终也是调用方法 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute 从org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache 获取

    (2) createTransactionIfNecessary方法准备事务相关东西

    org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary 方法源码如下:

        protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
                @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
    
            // If no name specified, apply method identification as transaction name.
            if (txAttr != null && txAttr.getName() == null) {
                txAttr = new DelegatingTransactionAttribute(txAttr) {
                    @Override
                    public String getName() {
                        return joinpointIdentification;
                    }
                };
            }
    
            TransactionStatus status = null;
            if (txAttr != null) {
                if (tm != null) {
                    status = tm.getTransaction(txAttr);
                }
                else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                                "] because no transaction manager has been configured");
                    }
                }
            }
            return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
        }

    tm.getTransaction(txAttr); 方法 调用org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction 获取事务

        @Override
        public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
                throws TransactionException {
    
            // Use defaults if no transaction definition given.
            TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    
            Object transaction = doGetTransaction();
            boolean debugEnabled = logger.isDebugEnabled();
    
            if (isExistingTransaction(transaction)) {
                // Existing transaction found -> check propagation behavior to find out how to behave.
                return handleExistingTransaction(def, transaction, debugEnabled);
            }
    
            // Check definition settings for new transaction.
            if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
                throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
            }
    
            // No existing transaction found -> check propagation behavior to find out how to proceed.
            if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
                throw new IllegalTransactionStateException(
                        "No existing transaction found for transaction marked with propagation 'mandatory'");
            }
            else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
                    def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
                    def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
                SuspendedResourcesHolder suspendedResources = suspend(null);
                if (debugEnabled) {
                    logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
                }
                try {
                    return startTransaction(def, transaction, debugEnabled, suspendedResources);
                }
                catch (RuntimeException | Error ex) {
                    resume(null, suspendedResources);
                    throw ex;
                }
            }
            else {
                // Create "empty" transaction: no actual transaction, but potentially synchronization.
                if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
                    logger.warn("Custom isolation level specified but no actual transaction initiated; " +
                            "isolation level will effectively be ignored: " + def);
                }
                boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
                return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
            }
        }

    这里会判断是否有事务,没有事务的情况下判断事务的传播行为,然后会调用org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction开启事务

        private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
                boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
    
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            doBegin(transaction, definition);
            prepareSynchronization(status, definition);
            return status;
        }

      首先创建DefaultTransactionStatus 会记录事务的一些属性到该对象;然后调用 org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin 开启事务

        protected void doBegin(Object transaction, TransactionDefinition definition) {
            DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
            Connection con = null;
    
            try {
                if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                    Connection newCon = this.obtainDataSource().getConnection();
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
                    }
    
                    txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
                }
    
                txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
                con = txObject.getConnectionHolder().getConnection();
                Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
                txObject.setPreviousIsolationLevel(previousIsolationLevel);
                txObject.setReadOnly(definition.isReadOnly());
                if (con.getAutoCommit()) {
                    txObject.setMustRestoreAutoCommit(true);
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                    }
    
                    con.setAutoCommit(false);
                }
    
                this.prepareTransactionalConnection(con, definition);
                txObject.getConnectionHolder().setTransactionActive(true);
                int timeout = this.determineTimeout(definition);
                if (timeout != -1) {
                    txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
                }
    
                if (txObject.isNewConnectionHolder()) {
                    TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
                }
    
            } catch (Throwable var7) {
                if (txObject.isNewConnectionHolder()) {
                    DataSourceUtils.releaseConnection(con, this.obtainDataSource());
                    txObject.setConnectionHolder((ConnectionHolder)null, false);
                }
    
                throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
            }
        }

    做完上面操作然后调用org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo 将相关信息封装到一个TransactionInfo 对象中:创建对象,然后txInfo.bindToThread与当前线程进行绑定(ThreadLocal)

        protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
                @Nullable TransactionAttribute txAttr, String joinpointIdentification,
                @Nullable TransactionStatus status) {
    
            TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
            if (txAttr != null) {
                // We need a transaction for this method...
                if (logger.isTraceEnabled()) {
                    logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
                }
                // The transaction manager will flag an error if an incompatible tx already exists.
                txInfo.newTransactionStatus(status);
            }
            else {
                // The TransactionInfo.hasTransaction() method will return false. We created it only
                // to preserve the integrity of the ThreadLocal stack maintained in this class.
                if (logger.isTraceEnabled()) {
                    logger.trace("No need to create transaction for [" + joinpointIdentification +
                            "]: This method is not transactional.");
                }
            }
    
            // We always bind the TransactionInfo to the thread, even if we didn't create
            // a new transaction here. This guarantees that the TransactionInfo stack
            // will be managed correctly even if no transaction was created by this aspect.
            txInfo.bindToThread();
            return txInfo;
        }

    (3) 调用业务方法

    invocation.proceedWithInvocation();

    (4) 如果捕捉到异常之后调用方法completeTransactionAfterThrowing 进行事务异常处理; 然后将异常再向外抛(finally代码块清掉事务相关状态)

    org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing 如下:

        protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
            if (txInfo != null && txInfo.getTransactionStatus() != null) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
                            "] after exception: " + ex);
                }
                if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
                    try {
                        txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                    }
                    catch (TransactionSystemException ex2) {
                        logger.error("Application exception overridden by rollback exception", ex);
                        ex2.initApplicationException(ex);
                        throw ex2;
                    }
                    catch (RuntimeException | Error ex2) {
                        logger.error("Application exception overridden by rollback exception", ex);
                        throw ex2;
                    }
                }
                else {
                    // We don't roll back on this exception.
                    // Will still roll back if TransactionStatus.isRollbackOnly() is true.
                    try {
                        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                    }
                    catch (TransactionSystemException ex2) {
                        logger.error("Application exception overridden by commit exception", ex);
                        ex2.initApplicationException(ex);
                        throw ex2;
                    }
                    catch (RuntimeException | Error ex2) {
                        logger.error("Application exception overridden by commit exception", ex);
                        throw ex2;
                    }
                }
            }
        }

    如果是支持回滚的异常类型会进行回滚, org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn方法如下:(也就是默认是Error 和 RuntimeException 类型的异常会进行回滚)

        public boolean rollbackOn(Throwable ex) {
            return (ex instanceof RuntimeException || ex instanceof Error);
        }

    调用org.springframework.transaction.support.AbstractPlatformTransactionManager#rollback 进行回滚:

        public final void rollback(TransactionStatus status) throws TransactionException {
            if (status.isCompleted()) {
                throw new IllegalTransactionStateException(
                        "Transaction is already completed - do not call commit or rollback more than once per transaction");
            }
    
            DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
            processRollback(defStatus, false);
        }

    org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback:

        private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
            try {
                boolean unexpectedRollback = unexpected;
    
                try {
                    triggerBeforeCompletion(status);
    
                    if (status.hasSavepoint()) {
                        if (status.isDebug()) {
                            logger.debug("Rolling back transaction to savepoint");
                        }
                        status.rollbackToHeldSavepoint();
                    }
                    else if (status.isNewTransaction()) {
                        if (status.isDebug()) {
                            logger.debug("Initiating transaction rollback");
                        }
                        doRollback(status);
                    }
                    else {
                        // Participating in larger transaction
                        if (status.hasTransaction()) {
                            if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
                                if (status.isDebug()) {
                                    logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
                                }
                                doSetRollbackOnly(status);
                            }
                            else {
                                if (status.isDebug()) {
                                    logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
                                }
                            }
                        }
                        else {
                            logger.debug("Should roll back transaction but cannot - no transaction available");
                        }
                        // Unexpected rollback only matters here if we're asked to fail early
                        if (!isFailEarlyOnGlobalRollbackOnly()) {
                            unexpectedRollback = false;
                        }
                    }
                }
                catch (RuntimeException | Error ex) {
                    triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
                    throw ex;
                }
    
                triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
    
                // Raise UnexpectedRollbackException if we had a global rollback-only marker
                if (unexpectedRollback) {
                    throw new UnexpectedRollbackException(
                            "Transaction rolled back because it has been marked as rollback-only");
                }
            }
            finally {
                cleanupAfterCompletion(status);
            }
        }

    最终调用到: org.springframework.jdbc.datasource.DataSourceTransactionManager#doRollback 进行回滚:

        protected void doRollback(DefaultTransactionStatus status) {
            DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
            Connection con = txObject.getConnectionHolder().getConnection();
            if (status.isDebug()) {
                logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
            }
            try {
                con.rollback();
            }
            catch (SQLException ex) {
                throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
            }
        }

    (5) 如果没有捕捉到异常,finally代码块清掉事务相关状态; 然后对事务进行commit。

     org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning:

        protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
            if (txInfo != null && txInfo.getTransactionStatus() != null) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
                }
                txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
            }
        }

    org.springframework.transaction.support.AbstractPlatformTransactionManager#commit:

        public final void commit(TransactionStatus status) throws TransactionException {
            if (status.isCompleted()) {
                throw new IllegalTransactionStateException(
                        "Transaction is already completed - do not call commit or rollback more than once per transaction");
            }
    
            DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
            if (defStatus.isLocalRollbackOnly()) {
                if (defStatus.isDebug()) {
                    logger.debug("Transactional code has requested rollback");
                }
                processRollback(defStatus, false);
                return;
            }
    
            if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
                if (defStatus.isDebug()) {
                    logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
                }
                processRollback(defStatus, true);
                return;
            }
    
            processCommit(defStatus);
        }

    org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit:

        private void processCommit(DefaultTransactionStatus status) throws TransactionException {
            try {
                boolean beforeCompletionInvoked = false;
    
                try {
                    boolean unexpectedRollback = false;
                    prepareForCommit(status);
                    triggerBeforeCommit(status);
                    triggerBeforeCompletion(status);
                    beforeCompletionInvoked = true;
    
                    if (status.hasSavepoint()) {
                        if (status.isDebug()) {
                            logger.debug("Releasing transaction savepoint");
                        }
                        unexpectedRollback = status.isGlobalRollbackOnly();
                        status.releaseHeldSavepoint();
                    }
                    else if (status.isNewTransaction()) {
                        if (status.isDebug()) {
                            logger.debug("Initiating transaction commit");
                        }
                        unexpectedRollback = status.isGlobalRollbackOnly();
                        doCommit(status);
                    }
                    else if (isFailEarlyOnGlobalRollbackOnly()) {
                        unexpectedRollback = status.isGlobalRollbackOnly();
                    }
    
                    // Throw UnexpectedRollbackException if we have a global rollback-only
                    // marker but still didn't get a corresponding exception from commit.
                    if (unexpectedRollback) {
                        throw new UnexpectedRollbackException(
                                "Transaction silently rolled back because it has been marked as rollback-only");
                    }
                }
                catch (UnexpectedRollbackException ex) {
                    // can only be caused by doCommit
                    triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
                    throw ex;
                }
                catch (TransactionException ex) {
                    // can only be caused by doCommit
                    if (isRollbackOnCommitFailure()) {
                        doRollbackOnCommitException(status, ex);
                    }
                    else {
                        triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
                    }
                    throw ex;
                }
                catch (RuntimeException | Error ex) {
                    if (!beforeCompletionInvoked) {
                        triggerBeforeCompletion(status);
                    }
                    doRollbackOnCommitException(status, ex);
                    throw ex;
                }
    
                // Trigger afterCommit callbacks, with an exception thrown there
                // propagated to callers but the transaction still considered as committed.
                try {
                    triggerAfterCommit(status);
                }
                finally {
                    triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
                }
    
            }
            finally {
                cleanupAfterCompletion(status);
            }
        }

      可以看到最后也是调用doCommit(status);保存事务信息。org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit:

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

    总结:事务过程中几个重要的类

    (1) org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration 事务自动配置的相关类

    (2) org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor 可以理解为切面Aspect的角色(内部维护Point与Advisor)

    (3) org.springframework.transaction.interceptor.TransactionAttributeSource 用于获取TransactionAttribute 事务属性,也就是读取@Transactional 注解上的相关属性

    (4) org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#TransactionAttributeSourcePointcut (是否需要进行事务的控制是在这个类进行判断的)

    (5) org.springframework.transaction.interceptor.TransactionInterceptor 事务拦截器。 (对事务的处理是在这个类)

    (6) org.springframework.transaction.interceptor.TransactionAttribute 封装事物属性的接口, 也就是封装@Transactional 注解上面的属性

    (7) org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo 封装事务信息的类,里面包括的重要属性如下:

            @Nullable
            private final PlatformTransactionManager transactionManager;
    
            @Nullable
            private final TransactionAttribute transactionAttribute;
    
            private final String joinpointIdentification;
    
            @Nullable
            private TransactionStatus transactionStatus;
    
            @Nullable
            private TransactionInfo oldTransactionInfo;

    (8) org.springframework.transaction.TransactionManager 事务管理器。 操作事务的方法都在这个类里面。用的最多的是org.springframework.transaction.PlatformTransactionManager 接口的实现类

    补充: 测试org.springframework.core.annotation.AnnotatedElementUtils#findMergedAnnotationAttributes 方法可以获取接口上的注解

     1. 注解类

    package com.xm.ggn.test.annotation;
    
    import java.lang.annotation.*;
    
    @Inherited
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnno1 {
    
        String value() default "111222";
    }

    2. 接口

    package com.xm.ggn.test.annotation;
    
    @MyAnno1("123456")
    public interface Interface1 {
    
        void fun1();
    }

    3. 类1

    package com.xm.ggn.test.annotation;
    
    public class Class1 implements Interface1{
    
        @Override
        public void fun1() {
            System.out.println("fun1 called!!!");
        }
    }

    4. Client

    package com.xm.ggn.test.annotation;
    
    import org.springframework.core.annotation.AnnotatedElementUtils;
    import org.springframework.core.annotation.AnnotationAttributes;
    
    public class Client {
    
        public static void main(String[] args) {
            AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
                    Class1.class, MyAnno1.class, false, false);
            System.out.println(attributes);
        }
    }

    5. 测试结果:

    补充:javax包下和Spring包下面注解@Transactional的区别 

      两者都可以实现事务的功能,是使用了两个不同的parser来进行解析。

    (1) javax包下的@Transactional 注解如下: javax 提供的注解,没有提供指定隔离级别、是否只读等参数,隔离级别也是数据库默认的隔离级别、只读默认是false。参考:org.springframework.transaction.annotation.JtaTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement) 创建的时候默认继承自org.springframework.transaction.support.DefaultTransactionDefinition#isolationLevel

    package javax.transaction;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import javax.enterprise.util.Nonbinding;
    import javax.interceptor.InterceptorBinding;
    
    @Inherited
    @InterceptorBinding
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Transactional {
        Transactional.TxType value() default Transactional.TxType.REQUIRED;
    
        @Nonbinding
        Class[] rollbackOn() default {};
    
        @Nonbinding
        Class[] dontRollbackOn() default {};
    
        public static enum TxType {
            REQUIRED,
            REQUIRES_NEW,
            MANDATORY,
            SUPPORTS,
            NOT_SUPPORTED,
            NEVER;
    
            private TxType() {
            }
        }
    }

    (2) Spring 包下的Transactional 注解如下:解析方法为 org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)

    package org.springframework.transaction.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.core.annotation.AliasFor;
    import org.springframework.transaction.TransactionDefinition;
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Transactional {
    
        @AliasFor("transactionManager")
        String value() default "";
    
        @AliasFor("value")
        String transactionManager() default "";
    
        Propagation propagation() default Propagation.REQUIRED;
    
        Isolation isolation() default Isolation.DEFAULT;
    
        int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    
        boolean readOnly() default false;
    
        Class<? extends Throwable>[] rollbackFor() default {};
    
        String[] rollbackForClassName() default {};
    
        Class<? extends Throwable>[] noRollbackFor() default {};
    
        String[] noRollbackForClassName() default {};
    
    }

    补充:TransactionAttribute继承自接口 TransactionDefinition, TransactionDefinition 接口定义了事务传播行为和隔离级别的一些变量: 

    package org.springframework.transaction;
    
    import org.springframework.lang.Nullable;
    
    /**
     * Interface that defines Spring-compliant transaction properties.
     * Based on the propagation behavior definitions analogous to EJB CMT attributes.
     *
     * <p>Note that isolation level and timeout settings will not get applied unless
     * an actual new transaction gets started. As only {@link #PROPAGATION_REQUIRED},
     * {@link #PROPAGATION_REQUIRES_NEW} and {@link #PROPAGATION_NESTED} can cause
     * that, it usually doesn't make sense to specify those settings in other cases.
     * Furthermore, be aware that not all transaction managers will support those
     * advanced features and thus might throw corresponding exceptions when given
     * non-default values.
     *
     * <p>The {@link #isReadOnly() read-only flag} applies to any transaction context,
     * whether backed by an actual resource transaction or operating non-transactionally
     * at the resource level. In the latter case, the flag will only apply to managed
     * resources within the application, such as a Hibernate {@code Session}.
     *
     * @author Juergen Hoeller
     * @since 08.05.2003
     * @see PlatformTransactionManager#getTransaction(TransactionDefinition)
     * @see org.springframework.transaction.support.DefaultTransactionDefinition
     * @see org.springframework.transaction.interceptor.TransactionAttribute
     */
    public interface TransactionDefinition {
    
        /**
         * Support a current transaction; create a new one if none exists.
         * Analogous to the EJB transaction attribute of the same name.
         * <p>This is typically the default setting of a transaction definition,
         * and typically defines a transaction synchronization scope.
         */
        int PROPAGATION_REQUIRED = 0;
    
        /**
         * Support a current transaction; execute non-transactionally if none exists.
         * Analogous to the EJB transaction attribute of the same name.
         * <p><b>NOTE:</b> For transaction managers with transaction synchronization,
         * {@code PROPAGATION_SUPPORTS} is slightly different from no transaction
         * at all, as it defines a transaction scope that synchronization might apply to.
         * As a consequence, the same resources (a JDBC {@code Connection}, a
         * Hibernate {@code Session}, etc) will be shared for the entire specified
         * scope. Note that the exact behavior depends on the actual synchronization
         * configuration of the transaction manager!
         * <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do
         * not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW}
         * <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to
         * synchronization conflicts at runtime). If such nesting is unavoidable, make sure
         * to configure your transaction manager appropriately (typically switching to
         * "synchronization on actual transaction").
         * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
         * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
         */
        int PROPAGATION_SUPPORTS = 1;
    
        /**
         * Support a current transaction; throw an exception if no current transaction
         * exists. Analogous to the EJB transaction attribute of the same name.
         * <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY}
         * scope will always be driven by the surrounding transaction.
         */
        int PROPAGATION_MANDATORY = 2;
    
        /**
         * Create a new transaction, suspending the current transaction if one exists.
         * Analogous to the EJB transaction attribute of the same name.
         * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
         * on all transaction managers. This in particular applies to
         * {@link org.springframework.transaction.jta.JtaTransactionManager},
         * which requires the {@code javax.transaction.TransactionManager} to be
         * made available it to it (which is server-specific in standard Java EE).
         * <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
         * transaction synchronizations. Existing synchronizations will be suspended
         * and resumed appropriately.
         * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
         */
        int PROPAGATION_REQUIRES_NEW = 3;
    
        /**
         * Do not support a current transaction; rather always execute non-transactionally.
         * Analogous to the EJB transaction attribute of the same name.
         * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
         * on all transaction managers. This in particular applies to
         * {@link org.springframework.transaction.jta.JtaTransactionManager},
         * which requires the {@code javax.transaction.TransactionManager} to be
         * made available it to it (which is server-specific in standard Java EE).
         * <p>Note that transaction synchronization is <i>not</i> available within a
         * {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
         * will be suspended and resumed appropriately.
         * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
         */
        int PROPAGATION_NOT_SUPPORTED = 4;
    
        /**
         * Do not support a current transaction; throw an exception if a current transaction
         * exists. Analogous to the EJB transaction attribute of the same name.
         * <p>Note that transaction synchronization is <i>not</i> available within a
         * {@code PROPAGATION_NEVER} scope.
         */
        int PROPAGATION_NEVER = 5;
    
        /**
         * Execute within a nested transaction if a current transaction exists,
         * behave like {@link #PROPAGATION_REQUIRED} otherwise. There is no
         * analogous feature in EJB.
         * <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
         * specific transaction managers. Out of the box, this only applies to the JDBC
         * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
         * when working on a JDBC 3.0 driver. Some JTA providers might support
         * nested transactions as well.
         * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
         */
        int PROPAGATION_NESTED = 6;
    
    
        /**
         * Use the default isolation level of the underlying datastore.
         * All other levels correspond to the JDBC isolation levels.
         * @see java.sql.Connection
         */
        int ISOLATION_DEFAULT = -1;
    
        /**
         * Indicates that dirty reads, non-repeatable reads and phantom reads
         * can occur.
         * <p>This level allows a row changed by one transaction to be read by another
         * transaction before any changes in that row have been committed (a "dirty read").
         * If any of the changes are rolled back, the second transaction will have
         * retrieved an invalid row.
         * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
         */
        int ISOLATION_READ_UNCOMMITTED = 1;  // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
    
        /**
         * Indicates that dirty reads are prevented; non-repeatable reads and
         * phantom reads can occur.
         * <p>This level only prohibits a transaction from reading a row
         * with uncommitted changes in it.
         * @see java.sql.Connection#TRANSACTION_READ_COMMITTED
         */
        int ISOLATION_READ_COMMITTED = 2;  // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;
    
        /**
         * Indicates that dirty reads and non-repeatable reads are prevented;
         * phantom reads can occur.
         * <p>This level prohibits a transaction from reading a row with uncommitted changes
         * in it, and it also prohibits the situation where one transaction reads a row,
         * a second transaction alters the row, and the first transaction re-reads the row,
         * getting different values the second time (a "non-repeatable read").
         * @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
         */
        int ISOLATION_REPEATABLE_READ = 4;  // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;
    
        /**
         * Indicates that dirty reads, non-repeatable reads and phantom reads
         * are prevented.
         * <p>This level includes the prohibitions in {@link #ISOLATION_REPEATABLE_READ}
         * and further prohibits the situation where one transaction reads all rows that
         * satisfy a {@code WHERE} condition, a second transaction inserts a row
         * that satisfies that {@code WHERE} condition, and the first transaction
         * re-reads for the same condition, retrieving the additional "phantom" row
         * in the second read.
         * @see java.sql.Connection#TRANSACTION_SERIALIZABLE
         */
        int ISOLATION_SERIALIZABLE = 8;  // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;
    
    
        /**
         * Use the default timeout of the underlying transaction system,
         * or none if timeouts are not supported.
         */
        int TIMEOUT_DEFAULT = -1;
    
    
        /**
         * Return the propagation behavior.
         * <p>Must return one of the {@code PROPAGATION_XXX} constants
         * defined on {@link TransactionDefinition this interface}.
         * <p>The default is {@link #PROPAGATION_REQUIRED}.
         * @return the propagation behavior
         * @see #PROPAGATION_REQUIRED
         * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()
         */
        default int getPropagationBehavior() {
            return PROPAGATION_REQUIRED;
        }
    
        /**
         * Return the isolation level.
         * <p>Must return one of the {@code ISOLATION_XXX} constants defined on
         * {@link TransactionDefinition this interface}. Those constants are designed
         * to match the values of the same constants on {@link java.sql.Connection}.
         * <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
         * {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
         * transactions. Consider switching the "validateExistingTransactions" flag to
         * "true" on your transaction manager if you'd like isolation level declarations
         * to get rejected when participating in an existing transaction with a different
         * isolation level.
         * <p>The default is {@link #ISOLATION_DEFAULT}. Note that a transaction manager
         * that does not support custom isolation levels will throw an exception when
         * given any other level than {@link #ISOLATION_DEFAULT}.
         * @return the isolation level
         * @see #ISOLATION_DEFAULT
         * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
         */
        default int getIsolationLevel() {
            return ISOLATION_DEFAULT;
        }
    
        /**
         * Return the transaction timeout.
         * <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}.
         * <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
         * {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
         * transactions.
         * <p>Note that a transaction manager that does not support timeouts will throw
         * an exception when given any other timeout than {@link #TIMEOUT_DEFAULT}.
         * <p>The default is {@link #TIMEOUT_DEFAULT}.
         * @return the transaction timeout
         */
        default int getTimeout() {
            return TIMEOUT_DEFAULT;
        }
    
        /**
         * Return whether to optimize as a read-only transaction.
         * <p>The read-only flag applies to any transaction context, whether backed
         * by an actual resource transaction ({@link #PROPAGATION_REQUIRED}/
         * {@link #PROPAGATION_REQUIRES_NEW}) or operating non-transactionally at
         * the resource level ({@link #PROPAGATION_SUPPORTS}). In the latter case,
         * the flag will only apply to managed resources within the application,
         * such as a Hibernate {@code Session}.
         * <p>This just serves as a hint for the actual transaction subsystem;
         * it will <i>not necessarily</i> cause failure of write access attempts.
         * A transaction manager which cannot interpret the read-only hint will
         * <i>not</i> throw an exception when asked for a read-only transaction.
         * @return {@code true} if the transaction is to be optimized as read-only
         * ({@code false} by default)
         * @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean)
         * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
         */
        default boolean isReadOnly() {
            return false;
        }
    
        /**
         * Return the name of this transaction. Can be {@code null}.
         * <p>This will be used as the transaction name to be shown in a
         * transaction monitor, if applicable (for example, WebLogic's).
         * <p>In case of Spring's declarative transactions, the exposed name will be
         * the {@code fully-qualified class name + "." + method name} (by default).
         * @return the name of this transaction ({@code null} by default}
         * @see org.springframework.transaction.interceptor.TransactionAspectSupport
         * @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName()
         */
        @Nullable
        default String getName() {
            return null;
        }
    
    
        // Static builder methods
    
        /**
         * Return an unmodifiable {@code TransactionDefinition} with defaults.
         * <p>For customization purposes, use the modifiable
         * {@link org.springframework.transaction.support.DefaultTransactionDefinition}
         * instead.
         * @since 5.2
         */
        static TransactionDefinition withDefaults() {
            return StaticTransactionDefinition.INSTANCE;
        }
    
    }
    【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】
  • 相关阅读:
    线程基础之进程,线程,任务
    Jobs深入学习
    Quartz的API简介及Jobs和Trigger介绍
    Quartz入门及简单实现
    maven仓库配置阿里云镜像
    Activiti图表bpmn对应的xml文件
    Activiti流程设计工具
    Activiti的25张表
    subprocess.Popen指令包含中文导致乱码问题解决
    Qt5.9使用QWebEngineView加载网页速度非常慢,问题解决
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/14706202.html
Copyright © 2020-2023  润新知