Spring transactional注解源码分析

总体理解

事务依托AOP技术,适配AOP完成事务功能。

  1. 切面类拦截成功则创建代理

  1. 代理以责任链模式执行切面

核心类

Aop核心类

扩展点 AbsractAutoProxyCreator

代理类 AopProxy

JdkDynamicProxy

CglibAopProxy

切面类执行器 ReflectiveMethodInvocation

事务

事务切面类 BeanFactoryTransactionAttributeSourceAdvisor
事务拦截器 TransactionInterceptor

背景知识

  1. 熟悉Spring Bean 生命周期

  1. 了解Spring Aop原理

  1. 总结Spring Aop

maven坐标

引入spring tx模块

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>

分析

学习完spring aop知识。我们可以知道他是使用 beanPostProcessor接口postProcessAfterInitialization 方法处理。“如果切面拦截这个类的方法,那么将创建代理”

核心类

BeanFactoryTransactionAttributeSourceAdvisor

AnnotationTransactionAttributeSource

TransactionAttributeSourcePointcut

TransactionInterceptor

源码

AbstractAdvisorAutoProxyCreator#findCandidateAdvisors

查找可能的切面

    protected List<Advisor> findCandidateAdvisors() {
        Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
        return this.advisorRetrievalHelper.findAdvisorBeans();
    }

advisorRetrievalHelper#findAdvisorBean

源码

public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        String[] advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the auto-proxy creator apply to them!
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Advisor.class, true, false);
            this.cachedAdvisorBeanNames = advisorNames;
        }
        List<Advisor> advisors = new ArrayList<>();
        for (String name : advisorNames) {
            if (isEligibleBean(name)) {
                if (this.beanFactory.isCurrentlyInCreation(name)) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Skipping currently created advisor '" + name + "'");
                    }
                }
                else {                    
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));                                        
                }
            }
        }
        return advisors;
    }

分析

查找ioc容器中类型是Advisor.class的BeanDefinition。并且我们期望bean来自spring-tx模块下。

于是我们发现目标类 BeanFactoryTransactionAttributeSourceAdvisor

BeanFactoryTransactionAttributeSourceAdvisor简称 transactionAdvisor

问题

BeanFactoryTransactionAttributeSourceAdvisor何时注册到ioc容器呢?

我们全局搜索下BeanFactoryTransactionAttributeSourceAdvisor

发现如下类:

  1. EnableTransactionManagement 是个注解,importTransactionManagementConfigurationSelector

  1. TransactionManagementConfigurationSelector 实现了ImportSelector接口将执行selectImports方法。注册ProxyTransactionManagementConfiguration到ioc容器

  1. ProxyTransactionManagementConfiguration 以编程方式 @Bean注册 BeanFactoryTransactionAttributeSourceAdvisor。

为什么Springboot 没有标记EnableTransactionManagement注解。事务仍然生效了呢?

答:Springboot开启了自动装配。TransactionAutoConfiguration 标记了EnableTransactionManagement注解。


    @Configuration(proxyBeanMethods = false)
    @ConditionalOnBean(TransactionManager.class)
    @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
    public static class EnableTransactionManagementConfiguration {

        @Configuration(proxyBeanMethods = false)
        @EnableTransactionManagement(proxyTargetClass = false)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
        public static class JdkDynamicAutoProxyConfiguration {

        }

        @Configuration(proxyBeanMethods = false)
        @EnableTransactionManagement(proxyTargetClass = true)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                matchIfMissing = true)
        public static class CglibAutoProxyConfiguration {

        }

transactionAdvisor类图

源码

    private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
        @Override
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return transactionAttributeSource;
        }
    };
    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }

    /**
     * Set the {@link ClassFilter} to use for this pointcut.
     * Default is {@link ClassFilter#TRUE}.
     */
    public void setClassFilter(ClassFilter classFilter) {
        this.pointcut.setClassFilter(classFilter);
    }

依类图和源码可知:

  1. TransactionInterceptor 实现了Advice接口。 并注入到BeanFactoryTransactionAttributeSourceAdvisor。

  1. TransactionAttributeSourcePointcut实现了Point接口,并注入到BeanFactoryTransactionAttributeSourceAdvisor。

  1. 并且继承了StaticMethodMatcherPointcut 抽象类。而StaticMethodMatcherPointcut.getMethodMatcher方法返回是其自己

  1. AnnotationTransactionAttributeSource注入到TransactionAttributeSourcePointcut。

transactionAdvisor初始化

ProxyTransactionManagementConfiguration 完成transactionAdvisor初始化工作

该配置类将AnnotationTransactionAtrributeSourceTransactionInterceptor 注入到BeanFactoryTransactionAttributeSourceAdvisor

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;
    }

}

AOP工作

postProcessAfterInitialization

Pointcut 切入点能否拦截目标Bd的方法。

摘一部分Aop源码翻看

AopUtils.findAdvisorsThatCanApply

检查目标类是否有被切面拦截!核心是取Advisor.pointCut是否拦截bd的方法。

    public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
 
        List<Advisor> eligibleAdvisors = new ArrayList<>();
 
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        for (Advisor candidate : candidateAdvisors) {
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }
    public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
   
         if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pca = (PointcutAdvisor) advisor;
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
       
    }

AopUtils.canApply

    public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        
        if (!pc.getClassFilter().matches(targetClass)) {
            return false;
        }

        MethodMatcher methodMatcher = pc.getMethodMatcher();
        if (methodMatcher == MethodMatcher.TRUE) {
            // No need to iterate the methods if we're matching any method anyway...
            return true;
        }

        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
            introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set<Class<?>> classes = new LinkedHashSet<>();
        if (!Proxy.isProxyClass(targetClass)) {
            classes.add(ClassUtils.getUserClass(targetClass));
        }
        classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

        for (Class<?> clazz : classes) {
            Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
            for (Method method : methods) {
                if (introductionAwareMethodMatcher != null ?
                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                        methodMatcher.matches(method, targetClass)) {
                    return true;
                }
            }
        }

        return false;
    }

看Aop 整理出问题?

  1. transactionAdvisor.pointcut是什么类型?

  1. pointcut如何完成getClassFilter().matches工作?

  1. pointcut.getMethodMatcher如何完成matchs工作?

  1. pointcut 如何读取事务配置的呢?

  1. 如何开启数据库事务呢?

回答问题1,transactionAdvisor.pointcut是什么类型

  1. transactionAdvisor的类图和 源码可得:pointcutTransactionAttributeSourcePointcut

回答问题2,pointcut如何完成getClassFilter().matches工作

查看源码得Pointcut 的classFilter实现类是TransactionAttributeSourceClassFilter。matchs工作最终交给AnnotationsUtils.isCandidateClass处理的,一般情况都会返回true。

TransactionAttributeSourcePointcut

源码

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

    protected TransactionAttributeSourcePointcut() {
        setClassFilter(new TransactionAttributeSourceClassFilter());
    }

    /**
     * {@link ClassFilter} that delegates to {@link TransactionAttributeSource#isCandidateClass}
     * for filtering classes whose methods are not worth searching to begin with.
     */
    private class TransactionAttributeSourceClassFilter implements ClassFilter {

        @Override
        public boolean matches(Class<?> clazz) {
            if (TransactionalProxy.class.isAssignableFrom(clazz) ||
                    TransactionManager.class.isAssignableFrom(clazz) ||
                    PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
                return false;
            }
            TransactionAttributeSource tas = getTransactionAttributeSource();
            return (tas == null || tas.isCandidateClass(clazz));
        }
    }

分析

重写了ClassFilter.matchs方法。对应AopUtils.canApply代码。

说明 TransactionAttributeSourceClassFilter#matchs 方法将被执行,最终走到AnnotationTransactionAttributeSource#isCandidateClass 方法。

    if (!pc.getClassFilter().matches(targetClass)) {
            return false;
        }
AnnotationTransactionAttributeSource
源码
    private final Set<TransactionAnnotationParser> annotationParsers;
 
    public AnnotationTransactionAttributeSource() {
        this(true);
    }
    public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
        this.publicMethodsOnly = publicMethodsOnly;
        this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
    }
    @Override
    public boolean isCandidateClass(Class<?> targetClass) {
        for (TransactionAnnotationParser parser : this.annotationParsers) {
            if (parser.isCandidateClass(targetClass)) {
                return true;
            }
        }
        return false;
    }
分析

发现isCandidateClass 调用SpringTransactionAnnotationParser.isCandidateClass 方法处理

SpringTransactionAnnotationParser
源码
    @Override
    public boolean isCandidateClass(Class<?> targetClass) {
        return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
    }
AnnotationUtils#isCandidateClass
源码
    public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {
        return isCandidateClass(clazz, annotationType.getName());
    }
    public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
        if (annotationName.startsWith("java.")) {
            return true;
        }
        if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
            return false;
        }
        return true;
    }
    public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
        if (annotationName.startsWith("java.")) {
            return true;
        }
        if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
            return false;
        }
        return true;
    }
    static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {
        return (type.getName().startsWith("java.") || type == Ordered.class);
    }

见源码可得:isCandidateClass 必然返回true

回答问题3:pointcut.getMethodMatcher如何完成matchs工作?

答案:方法访问修饰符必须是public级别,必须标记transactional注解 才返回true否则false。

TransactionAttributeSourcePointcut的getMatchMacher对象返回是其自己。matchs工作是由其自己完成。

见源码可得:内部交由TransactionAttributeSource.getTransactionAttribute 完成。

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

查询getTransactionAttribute和computeTransactionAttribute方法。得出标记transactional注解的方法必须是public限定的。

method必须是public 、必须标注了transactional注解才能开启事务。

    private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);

    public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
            // 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 dta = (DefaultTransactionAttribute) txAttr;
                    dta.setDescriptor(methodIdentification);
                    dta.resolveAttributeStrings(this.embeddedValueResolver);
                }

                this.attributeCache.put(cacheKey, txAttr);
            }
            return txAttr;
        
    }
    protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
        // Don't allow non-public methods, as configured.
        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;
    }

回答问题4: pointcut 如何读取事务配置的呢?

findTransactionAttribute 查询事物配置并保存内部的attributeCache

findTransactionAttribute
    @Override
    @Nullable
    protected TransactionAttribute findTransactionAttribute(Method method) {
        return determineTransactionAttribute(method);
    }
    @Nullable
    protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
        for (TransactionAnnotationParser parser : this.annotationParsers) {
            TransactionAttribute attr = parser.parseTransactionAnnotation(element);
            if (attr != null) {
                return attr;
            }
        }
        return null;
    }
    public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
        AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
                element, Transactional.class, false, false);
        if (attributes != null) {
            return parseTransactionAnnotation(attributes);
        }
        else {
            return null;
        }
    }

    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());
        String timeoutString = attributes.getString("timeoutString");
        Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
                "Specify 'timeout' or 'timeoutString', not both");
        rbta.setTimeoutString(timeoutString);

        rbta.setReadOnly(attributes.getBoolean("readOnly"));
        rbta.setQualifier(attributes.getString("value"));
        rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));

        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;
    }

回答问题5: 如何开启数据库事务呢?

回答:使用 TransactionAspectSupport#invokeWithinTransaction 开启数据库事务

分析:开启数据库事务处理业务在创建代理后执行方法。

摘JdkDynamicAopProxy代码说明问题

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);       
                // We need to create a method invocation...
                MethodInvocation invocation =
                        new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }

这块代码是将advisor 转化成methodIntecerptor.传入连接点调用器MethodIncation执行。

advisor 转化成methodIntecerptor
源码
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<>(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[0]);
    }
分析

TransactionInterceptor是Advice实现类。

transactionAdvisor的advice是TransactionInterceptor.所以将转化成TransactionInterceptor。

TransactionInterceptor 完成事务工作

由于调用入口来自ReflectiveMethodInvation.proceed 分析过程请看 spring aop总结

摘部分代码

public Object proceed() throws Throwable {
         // We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
          return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    
    }

进而调用MethodInterceptor.invoke方法最终调用TransactionAspectSupport#invokeWithinTransaction

    public Object invoke(MethodInvocation invocation) throws Throwable {

        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

        // Adapt to TransactionAspectSupport's invokeWithinTransaction...
       //适配 TransactionAspectSupport invokeWithinTransaction
        return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
       //....
    }

TransactionAspectSupport

    @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.
        // 读取Tranactional注解的属性
        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        //拉取事务管理器 
        final TransactionManager tm = determineTransactionManager(txAttr);

    

        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 (retVal != null && 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 {
            Object result;
            final ThrowableHolder throwableHolder = new ThrowableHolder();

            // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
            try {
                result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
                    TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
                    try {
                        Object retVal = invocation.proceedWithInvocation();
                        if (retVal != null && 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);
                    }
                });
            }
            catch (ThrowableHolderException ex) {
                throw ex.getCause();
            }
            catch (TransactionSystemException ex2) {
                
                throw ex2;
            }
            catch (Throwable ex2) {
                
                throw ex2;
            }

            // Check result state: It might indicate a Throwable to rethrow.
            if (throwableHolder.throwable != null) {
                throw throwableHolder.throwable;
            }
            return result;
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jiguansheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值