spring事务失效场景(@Transactional)

179 阅读2分钟

springboot使用事务

  • 在类或者方法上加上@Transactional注解即可
@Transactional  
public void addOrder(){  
    //业务修改数据一  
    ******  
    //业务修改数据二  
    ******  
}

@Transactional原理

  • 在springboot中由于自动装配的原因所以不需要在启动类上加@EnableTransactionManagement注解
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

以下是TransactionAutoConfiguration的内部类,查看后发现在内部包含了@EnableTransactionManagement

@ConditionalOnBean({TransactionManager.class})
@ConditionalOnMissingBean({AbstractTransactionManagementConfiguration.class})
public static class EnableTransactionManagementConfiguration {
    public EnableTransactionManagementConfiguration() {
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @EnableTransactionManagement(
        proxyTargetClass = true
    )
    @ConditionalOnProperty(
        prefix = "spring.aop",
        name = {"proxy-target-class"},
        havingValue = "true",
        matchIfMissing = true
    )
    //默认使用cglib代理
    public static class CglibAutoProxyConfiguration {
        public CglibAutoProxyConfiguration() {
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @EnableTransactionManagement(
        proxyTargetClass = false
    )
    @ConditionalOnProperty(
        prefix = "spring.aop",
        name = {"proxy-target-class"},
        havingValue = "false",
        matchIfMissing = false
    )
    public static class JdkDynamicAutoProxyConfiguration {
        public JdkDynamicAutoProxyConfiguration() {
        }
    }
}
  • EnableTransactionManagement源码
@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 2147483647;
}
  • TransactionManagementConfigurationSelector源码
protected String[] selectImports(AdviceMode adviceMode) {
    switch(adviceMode) {
    case PROXY:
        return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
    case ASPECTJ:
        return new String[]{this.determineTransactionAspectClass()};
    default:
        return null;
    }
}
  • ProxyTransactionManagementConfiguration源码
@Bean
@Role(2)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
    TransactionInterceptor interceptor = new TransactionInterceptor();
    interceptor.setTransactionAttributeSource(transactionAttributeSource);
    if (this.txManager != null) {
        interceptor.setTransactionManager(this.txManager);
    }

    return interceptor;
}
  • TransactionInterceptor主要源码
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
    Method var10001 = invocation.getMethod();
    invocation.getClass();
    return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
}
  • invokeWithinTransaction方法中主要关注三个方法 createTransactionIfNecessary:开启事务 completeTransactionAfterThrowing:出现异常后回滚
    commitTransactionAfterReturning:任务结束后提交事务
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
    TransactionAttributeSource tas = this.getTransactionAttributeSource();
    TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
    TransactionManager tm = this.determineTransactionManager(txAttr);
    if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
        TransactionAspectSupport.ReactiveTransactionSupport txSupport = (TransactionAspectSupport.ReactiveTransactionSupport)this.transactionSupportCache.computeIfAbsent(method, (key) -> {
            if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && TransactionAspectSupport.KotlinDelegate.isSuspend(method)) {
                throw new TransactionUsageException("Unsupported annotated transaction on suspending function detected: " + method + ". Use TransactionalOperator.transactional extensions instead.");
            } else {
                ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
                if (adapter == null) {
                    throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " + method.getReturnType());
                } else {
                    return new TransactionAspectSupport.ReactiveTransactionSupport(adapter);
                }
            }
        });
        return txSupport.invokeWithinTransaction(method, targetClass, invocation, txAttr, (ReactiveTransactionManager)tm);
    } else {
        PlatformTransactionManager ptm = this.asPlatformTransactionManager(tm);
        String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
        if (txAttr != null && ptm instanceof CallbackPreferringPlatformTransactionManager) {
            TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder();

            Object result;
            try {
                result = ((CallbackPreferringPlatformTransactionManager)ptm).execute(txAttr, (statusx) -> {
                    TransactionAspectSupport.TransactionInfo txInfo = this.prepareTransactionInfo(ptm, txAttr, joinpointIdentification, statusx);

                    Object var9;
                    try {
                        Object retVal = invocation.proceedWithInvocation();
                        if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {
                            retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, statusx);
                        }

                        var9 = retVal;
                        return var9;
                    } catch (Throwable var13) {
                        if (txAttr.rollbackOn(var13)) {
                            if (var13 instanceof RuntimeException) {
                                throw (RuntimeException)var13;
                            }

                            throw new TransactionAspectSupport.ThrowableHolderException(var13);
                        }

                        throwableHolder.throwable = var13;
                        var9 = null;
                    } finally {
                        this.cleanupTransactionInfo(txInfo);
                    }

                    return var9;
                });
            } catch (TransactionAspectSupport.ThrowableHolderException var20) {
                throw var20.getCause();
            } catch (TransactionSystemException var21) {
                if (throwableHolder.throwable != null) {
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    var21.initApplicationException(throwableHolder.throwable);
                }

                throw var21;
            } catch (Throwable var22) {
                if (throwableHolder.throwable != null) {
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                }

                throw var22;
            }

            if (throwableHolder.throwable != null) {
                throw throwableHolder.throwable;
            } else {
                return result;
            }
        } else {
            TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

            Object retVal;
            try {
                retVal = invocation.proceedWithInvocation();
            } catch (Throwable var18) {
                this.completeTransactionAfterThrowing(txInfo, var18);
                throw var18;
            } finally {
                this.cleanupTransactionInfo(txInfo);
            }

            if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {
                TransactionStatus status = txInfo.getTransactionStatus();
                if (status != null && txAttr != null) {
                    retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                }
            }

            this.commitTransactionAfterReturning(txInfo);
            return retVal;
        }
    }
}
  • 总结下来,事务是使用aop+动态代理实现的

失效原因

  1. 非public方法上加@Transactional
    框架只支持public修饰
  2. 加事务的方法在类内部使用this调用
    this调用无法使用通过代理类调用
  3. 被final、static修饰方法或类上加@Transactional
    cglib无法为final、static修饰的方法或类生成代理类
  4. 异常被捕捉
    异常被捕捉后方法上的事务认为是正常提交所以不会回滚
  5. 当前类未被spring管理