文章目录
Spring 自动事务管理的实现
SpringBoot @Transactional 注解未生效 阐述了Spring 自动事务管理的实现基础为 AOP,而 Spring 对事务的处理流程可概括为以下几步:
- 获取事务属性,即解析
@Transactional
注解中的参数- 获取事务管理器,就是在
@Transactional
注解中的transactionManager
参数- 收集事务信息,当前线程的事务状态,开启事务,并在当前线程中设置事务相关参数,标注当前线程是运行在事务中的
- 执行被拦截的方法业务代码,即被
@Transactional
注解标注的方法- 如果方法执行出现异常,做相关处理,可能会执行回滚操作或者设置回滚标志位
- 清理事务环境,将设置到
Threadlocal
中的相关变量清除- 提交事务
在具体分析时,结合 SpringBoot 的自动配置机制,可以将 Spring 事务的实现分为两个部分,即事务注解 Bean 的创建
与 事务执行的流程
1. 事务注解 Bean 的创建
-
事务自动配置类
TransactionAutoConfiguration
在程序启动时会被加载,其内部类EnableTransactionManagementConfiguration
启用了注解@EnableTransactionManagement
,从而开启了注解事务自动管理public static class EnableTransactionManagementConfiguration { @Configuration @EnableTransactionManagement(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false) public static class JdkDynamicAutoProxyConfiguration { } @Configuration @EnableTransactionManagement(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) public static class CglibAutoProxyConfiguration { } }
-
@EnableTransactionManagement
通过@Import(TransactionManagementConfigurationSelector.class)
导入了配置选择者TransactionManagementConfigurationSelector
@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; }
-
TransactionManagementConfigurationSelector#selectImports()
根据@EnableTransactionManagement
配置的增强模式AdviceMode
来决定使用哪种事务管理配置类
,通常默认采用PROXY
代理模式。以代理模式为例,容器启动过程中会通过配置的注册者AutoProxyRegistrar
将ProxyTransactionManagementConfiguration
注册到容器中,从而使配置生效public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { /** * Returns {@link ProxyTransactionManagementConfiguration} or * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY} * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, * respectively. */ @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; } } ...... }
-
ProxyTransactionManagementConfiguration
作为代理模式事务管理的配置类,其内配置了对事务管理举足轻重的三个 bean。其中BeanFactoryTransactionAttributeSourceAdvisor
作为事务增强的切面,切面内包含了TransactionInterceptor
实例作为增强,而AnnotationTransactionAttributeSource
实例则是用于生成匹配目标 bean 的切入点@Configuration public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { 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() { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource()); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } }
-
BeanFactoryTransactionAttributeSourceAdvisor
内部保存了切入点成员变量pointcut
,可以看到该成员变量实例为TransactionAttributeSourcePointcut
,这个切入点变量的作用就是匹配目标 beanpublic class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { @Nullable private TransactionAttributeSource transactionAttributeSource; private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override @Nullable protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } }; /** * Set the transaction attribute source which is used to find transaction * attributes. This should usually be identical to the source reference * set on the transaction interceptor itself. * @see TransactionInterceptor#setTransactionAttributeSource */ public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { this.transactionAttributeSource = transactionAttributeSource; } /** * Set the {@link ClassFilter} to use for this pointcut. * Default is {@link ClassFilter#TRUE}. */ public void setClassFilter(ClassFilter classFilter) { this.pointcut.setClassFilter(classFilter); } @Override public Pointcut getPointcut() { return this.pointcut; } }
-
通过以上步骤事务方法的切面就配置完成了,接下来就是切面与目标 bean 的匹配。这部分详细流程参考 Spring AOP 创建代理对象源码分析 可知匹配的最终过程是在
AopUtils#canApply()
方法中完成的,此处以事务增强的例子着重分析具体的匹配过程。首先进入AopUtils#canApply()
,可看到该方法中首先通过pc.getMethodMatcher()
获取到切入点中的方法匹配者MethodMatcher
对象,之后调用其matches()
方法将切面中的增强方法与目标 bean 进行匹配public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { ...... MethodMatcher methodMatcher = pc.getMethodMatcher(); ...... 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; }
-
从 步骤5 可知,事务增强的切入点对象实例为
TransactionAttributeSourcePointcut
,查看其matchs()
方法实现,可知其根据TransactionAttributeSource#getTransactionAttribute()
方法去获取事务属性,如果不为空即可匹配成功。而从 步骤4 又可知TransactionAttributeSource
的实现实例为AnnotationTransactionAttributeSource
@Override public boolean matches(Method method, Class<?> targetClass) { if (TransactionalProxy.class.isAssignableFrom(targetClass) || PlatformTransactionManager.class.isAssignableFrom(targetClass) || PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) { return false; } TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
-
AnnotationTransactionAttributeSource
继承自AbstractFallbackTransactionAttributeSource
,getTransactionAttribute()
方法的实现其实是在AbstractFallbackTransactionAttributeSource
中,其内部会调用computeTransactionAttribute()
方法去计算解析事务属性,这个方法的核心为调用findTransactionAttribute()
,需注意方法内会判断目标方法的访问修饰符,如果不是public
直接返回 nullpublic TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } ...... // We need to work it out. TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); ...... return txAttr; } }
-
findTransactionAttribute()
方法的实现在AnnotationTransactionAttributeSource
中,其核心流程为调用内部的determineTransactionAttribute()
方法解析目标方法,核心的解析类为TransactionAnnotationParser
接口的子类protected TransactionAttribute findTransactionAttribute(Method method) { return determineTransactionAttribute(method); } protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { for (TransactionAnnotationParser annotationParser : this.annotationParsers) { TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element); if (attr != null) { return attr; } } return null; }
-
TransactionAnnotationParser
接口的实现类有 3 个,其中以@Transactional
注解的事务方法由SpringTransactionAnnotationParser#parseTransactionAnnotation()
解析,经过该步骤会将@Transactional
的注解属性解析为事务属性TransactionAttribute
。至此,根据是否能够从目标方法上解析出事务属性,就能够判断事务切面与目标 bean 是否匹配,从而决定是否要创建目标 bean 的事务代理对象public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( element, Transactional.class, false, false); if (attributes != null) { return parseTransactionAnnotation(attributes); } else { return null; } }
2. 事务执行的流程
2.1 事务拦截器拦截方法的触发
-
事务注解的 bean 的代理对象被创建后,事务方法被调用时则触发 aop 方法拦截,
DynamicAdvisedInterceptor#intercept()
方法被调用,需注意如果方法的拦截链为空(类内部调用)并且方法是 public 的则不执行代理类的增强方法,也就不会有事务效果。不满足该条件则先创建CglibMethodInvocation
对象,并调用对象的proceed()
方法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(); try { if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool... target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // We can skip creating a MethodInvocation: just invoke the target directly. // Note that the final invoker must be an InvokerInterceptor, so we know // it does nothing but a reflective operation on the target, and no hot // swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // We need to create a method invocation... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
-
proceed()
方法的实现实际是在CglibMethodInvocation
的父类ReflectiveMethodInvocation
中。该方法会被递归调用,直到拦截裢最后一个拦截器的拦截方法通过 invokeJoinpoint() 真正执行,递归开始收束,整个拦截链上的拦截方法都会被执行。对于事务场景,此处调用事务拦截器TransactionInterceptor#invoke()
方法public Object proceed() throws Throwable { ...... else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
-
TransactionInterceptor#invoke()
方法其实只是调用了其父类TransactionAspectSupport
的invokeWithinTransaction()
方法,这个方法中执行@Transcational
修饰的方法的事务操作protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. // 1. 获取事务的属性 TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); // 2. 获取事务管理器 final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); // Spring 自动管理的声明式事务 if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. // 3. 解析事务属性,状态,开启事务,在Threadlocal中设置相关变量 TransactionInfo txInfo = createTransactionIfNecessary(tm, 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. // 4. 执行被@Transactional注解标注的业务方法 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception // 5. 如果允许出现异常,执行处理,如回滚操作 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { // 6.清理事务环境,将第3步中 ThreadLocal 中设置的变量清除 cleanupTransactionInfo(txInfo); } // 7.提交事务 commitTransactionAfterReturning(txInfo); return retVal; } // 手动管理的事务 else { ...... } }
2.2 事务执行的详细流程
2.2.1 获取事务属性
tas.getTransactionAttribute()
方法获取事务属性 TransactionAttribute,该部分与事务 bean 创建中的步骤8完全相同。通常情况下,在 bean 创建的时候已经扫描@Transactional
然后把属性存到缓存中,因此这里会从缓存里取,这样不用每次调用这个方法时都去解析一遍
2.2.2 获取事务管理器
determineTransactionManager()
方法获取PlatformTransactionManager 事务管理器。事务管理器保存着当前的数据源DataSource
,一个事务管理器对应一个数据源,它对外提供对该数据源的事务提交回滚等操作接口,以其子类实现 DataSourceTransactionManager
为例,其中提供了许多事务相关的操作方法。事务管理器的获取有两种途径:[1].首先从注解中解析获得 [2].如果注解中没有标明,则从容器中找到一个实现了PlatformTransactionManager接口的Bean,如果这种接口的bean有多个,同时没有使用@Primary标注的话,就会报错,具体可参考 DefaultListableBeanFactory#resolveNamedBean()方法的实现。
所以在写@Transactional
注解时尽量指定 transactionManager
参数,以便开启指定数据库的事务,否则当程序中有多个数据源时,如果使用了错误的事务管理器,事务显然是不会生效的
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
2.2.3 开启事务
-
createTransactionIfNecessary()
方法是事务开启的入口,其核心为调用tm.getTransaction()
去开启事务protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String 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()
方法有两种实现,此处以AbstractPlatformTransactionManager#getTransaction()
分析,可以看到其大致处理流程:[1]. 获得事务对象DataSourceTransactionObject [2]. 判断当前线程是否已经在事务中 [3]. 如果已经在一个事务中,则调用 handleExistingTransaction,根据不同的传播级别进行不同的操作 [4]. 如果不在一个事务中,则新建事务状态,并开启事务
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { // 1. 获取事务对象 Object transaction = doGetTransaction(); ..... // 2. 判断是否已经存在事务 if (isExistingTransaction(transaction)) { // Existing transaction found -> check propagation behavior to find out how to behave. // 3. 已经开启事务,根据不同传播级别执行不同操作 return handleExistingTransaction(definition, transaction, debugEnabled); } ...... // No existing transaction found -> check propagation behavior to find out how to proceed. if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { // 空挂起操作 SuspendedResourcesHolder suspendedResources = suspend(null); ...... try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); // 3. 新建事务状态 DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); // 4. 开启事务 doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } catch (RuntimeException | Error ex) { resume(null, suspendedResources); throw ex; } } ...... }
-
doGetTransaction()
的实现以DataSourceTransactionManager#doGetTransaction()
为例,可以看到其方法体首先新建了数据源事务对象DataSourceTransactionObject
,之后以当前数据源 DataSource 为 key 从TransactionSynchronizationManager
中获取到数据源的数据库连接,并将其设置到数据源事务对象中。需注意TransactionSynchronizationManager
这个类是每个线程事务同步管理的代理中心,用来管理事务用到的相关资源protected Object doGetTransaction() { DataSourceTransactionObject txObject = new DataSourceTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed()); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource()); txObject.setConnectionHolder(conHolder, false); return txObject; }
-
DataSourceTransactionManager#isExistingTransaction()
判断当前线程是否已经存在事务的逻辑很简单,就是通过数据源事务对象DataSourceTransactionObject
获取其数据库连接,判断该连接上的标识位transactionActive
是否为true
protected boolean isExistingTransaction(Object transaction) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive()); }
-
如果当前线程已经有事务存在了,就需要调用
AbstractPlatformTransactionManager#handleExistingTransaction()
处理事务传播问题。以传播级别PROPAGATION_REQUIRES_NEW
为例,可以看到 Spring 会执行一个suspend()
操作清空线程中保存的当前事务属性并将其存储到SuspendedResourcesHolder
对象中用于异常恢复,然后创建一个新的TransactionStatus
对象用于doBegin()
开启事务,整个过程也就是挂起当前事务开启一个新事务。之后对于REQUIRED的传播级别,则是直接返回,没有挂起和doBegin()
的操作。private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { ...... if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { ...... // 挂起事务 SuspendedResourcesHolder suspendedResources = suspend(transaction); try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); // 新建事务状态对象 DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } catch (RuntimeException | Error beginEx) { resumeAfterBeginException(transaction, suspendedResources, beginEx); throw beginEx; } } ...... // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED. ...... boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null); }
-
如果当前线程不存在事务,就调用
AbstractPlatformTransactionManager#newTransactionStatus()
方法新建DefaultTransactionStatus
事务状态对象,再调用doBegin()
开启事务。这里可以看到开启事务的具体操作con.setAutoCommit(false);
,其实就是原生JDBC
开启事务的方式,获取数据库连接再将其自动提交关闭protected void doBegin(Object transaction, TransactionDefinition definition) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; Connection con = null; ...... // 获取数据库连接 con = txObject.getConnectionHolder().getConnection(); Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition); txObject.setPreviousIsolationLevel(previousIsolationLevel); // Switch to manual commit if necessary. This is very expensive in some JDBC drivers, // so we don't want to do it unnecessarily (for example if we've explicitly // configured the connection pool to set it already). if (con.getAutoCommit()) { txObject.setMustRestoreAutoCommit(true); if (logger.isDebugEnabled()) { logger.debug("Switching JDBC Connection [" + con + "] to manual commit"); } // 开启数据库事务 con.setAutoCommit(false); } prepareTransactionalConnection(con, definition); txObject.getConnectionHolder().setTransactionActive(true); ...... }
2.2.4 异常回滚事务及清理事务信息
-
回到
TransactionAspectSupport#invokeWithinTransaction()
事务主流程,@Transactionl
注解的业务方法执行之后,就需要根据方法的执行结果来进行事务的提交或回滚。当业务方法发生异常时,Spring 会捕获该异常,并调用TransactionAspectSupport#completeTransactionAfterThrowing()
方法来决定是否回滚事务。可以看到txInfo.transactionAttribute.rollbackOn(ex)
决定来是否要进入回滚流程,真正的回滚操作由txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus())
完成protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { 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()); } ...... } } }
-
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus())
实际调用到了AbstractPlatformTransactionManager#rollback()
方法,其核心为调用processRollback()
方法,总共有三种情况:1、如果有保存点会回滚到保存点,这种对应着 NESTED 传播级别,利用了mysql的savepoint来实现 2、如果是一个新的事务,则真正执行回滚操作 3、如果是加入一个其他事务的话,则设置回滚标志位,交由父事务执行回滚操作
据此可以知道 Spring 会通过回滚标志位来影响事务的提交和回滚。有时候方法并没有抛出异常也会回滚,比如对于
REQUIRED
传播级别,A方法
调用B方法
,B方法
抛出异常后设置了回滚标志位,若A方法
捕获此异常并不再抛出异常,看起来A方法
会正常执行commit()
步骤,其实由于回滚标志位的存在,A方法对应的事务依旧会回滚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); } ...... }
-
不管事务都执行结果如何,都会在
finally
中执行cleanupTransactionInfo(txInfo)
,将此次事务相关信息从当前线程中清除
2.2.5 正常提交事务
@Transactionl
注解的业务方法执行成功,此时需要调用TransactionAspectSupport#commitTransactionAfterReturning()
方法进行事务的提交,这个方法的核心是txInfo.getTransactionManager().commit(txInfo.getTransactionStatus())
调用事务管理器的提交方法commit()
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());
}
}
- 与回滚类似,实际调用到了
AbstractPlatformTransactionManager#commit()
方法,最终调用到processCommit()
方法。此时也并不一定会执行提交操作,而是首先判断是否有savepoint保存点。有保存点,说明是内嵌在其他事务中的子事务,此时释放保存点,不会真正提交。其次判断是否是一个新的事务,如果是新事务直接执行提交。
至此,Spring 事务执行流程全部完成private void processCommit(DefaultTransactionStatus status) throws TransactionException { try { boolean beforeCompletionInvoked = false; try { ...... // 有保存点,说明是内嵌在其他事务中的子事务,释放保存点,不会真正提交 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"); } } ...... }