Spring事务注解@Transactional的流程和源码分析

Spring事务简介

Spring事务有两种方式:

  1. 编程式事务:编程式事务通常使用编程式事务管理API实现,比如Spring提供的PlatformTransactionManager接口,使用它操控事务。
  2. 声明式事务:注解式事务使用AOP(面向切面编程)来实现,在方法调用前后添加事务处理逻辑。除了XML配置外,Spring还支持使用注解来声明事务,目前使用注解是更方便和主流的方式。

Spring注解式事务原理

  1. Spring在实例化bean时会将带有@Transactional注解的类生成一个代理类对象,注入使用这个bean就是使用代理类对象。
  2. 这个代理类对象的方法拦截器类似Spring AOP的@Around,把业务方法包裹在事务的开启、事务的提交和事务的回滚,从而让代理类拦截器自动处理事务。
  3. 事务同步管理器将事务状态和信息存储在线程的ThreadLocal里,通过取ThreadLocal的事务信息实现方法嵌套调用中的事务信息传递。

以下这张流程图来自Spring官网:

在这里插入图片描述


Spring事务总览

Spring事务处理有以下几个重要组件:

  • 代理对象:假设SimpleServiceA是原始类,那么在Spring初始化bean时会进行增强生成代理类SimpleServiceA$$EnhancerBySpringCGLIB$$22b9f492的实例,代理对象对目标方法进行功能拦截器,自动完成事务的开启、提交和回滚。

  • 事务拦截器 TransactionInterceptor:事务拦截器将事务管理逻辑与业务代码进行解耦,作用类似于Spring AOP的一个拦截器,用于在方法调用前后实现事务管理。

  • 事务管理器 PlatformTransactionManager: Spring事务管理器负责管理事务的生命周期,包括事务的开始、提交或回滚等操作,其中最常用的事务管理器实现类是DataSourceTransactionManager,DataSourceTransactionManager除了上述的功能,还提供了方法使用数据源去获取和返还数据连接。

  • 事务同步管理器 TransactionSynchronizationManager:Spring 框架中用于管理事务同步的工具类,将事务信息和状态和线程绑定。

Spring事务组件关系图:

在这里插入图片描述

事务有关的信息和状态类

Spring事务在处理流程中有一系列的信息和状态类,让人眼花缭乱,下面来列举这些类,理清它们的关系。

  • TransactionInfo:事务信息,包含几乎所有事务信息和状态,在源码里简称为txInfo,内含TransactionAttribute(事务定义)、TransactionStatus(事务状态)和事务管理器。
  • TransactionAttribute:事务定义,里面存放着事务属性。
  • TransactionStatus:事务状态信息,在源码里简称为status,实现类为DefaultTransactionStatus,内含事务对象DataSourceTransactionObjectsavepoint保存点和挂起的数据库连接资源suspendedResources
  • DataSourceTransactionObject:事务对象,在源码里简称为txObjecttransaction,内含数据库连接ConnectionHolder
  • ConnectionHolder:数据库连接持有者,持有着数据库连接。

方法嵌套调用的情况下,每个事务拦截器进来后都会创建方法自身的TransactionInfo、TransactionStatus、DataSourceTransactionObject。

事务有关的信息和状态类关系图:

在这里插入图片描述

事务定义类

在事务处理中事务的定义类TransactionDefinition有很多衍生类和接口,它们的属性从事务注解@Transactional解析而来,在原码里名称为txAttr,关系如下:

在这里插入图片描述

其中DelegatingTransactionAttribute的类图:

在这里插入图片描述

图上那一系列类和接口,虽然比较绕,但都是和事务的定义有关。

事务对象

事务对象跟踪和管理与事务相关的状态和资源,包含数据库连接connectionHolder,实现类为DataSourceTransactionObject,在源码里简称为txObjecttransaction,它的类图如下:

在这里插入图片描述

事务管理器

事务管理器 PlatformTransactionManager 是Spring负责管理事务的生命周期的事务管理器,包括事务的开始、提交或回滚等操作,通过将事务信息和数据库连接绑定至线程实现多个嵌套方法间的传播。
事务管理器内部存放着数据源DataSource,能通过数据源获取和返还数据库连接,对事务的处理就是通过数据源的连接连接进行的。
事务管理器实现类有 DataSourceTransactionManager、JtaTransactionManager、WebSphereUowTransactionManager等,此处分析的是最常用的实现类DataSourceTransactionManager

事务管理器类图

在这里插入图片描述

@Transactional注解

@Target({ElementType.METHOD, ElementType.TYPE})
@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 {};}

@Target({ElementType.METHOD ElementType.TYPE}): 指定此注解可以应用的位置,可以是方法或类型(类和接口)。

@Retention(RetentionPolicy.RUNTIME): 表示此注解应在运行时保留,允许在运行时反射检查它。

注解属性:

  • valuetransactionManager的别名,和transactionManager的作用一样。
  • transactionManager:事务管理器,Spring事务支持使用多个事务管理器,可以通过该属性使用指定事务管理器。
  • propagation: 事务传播方式,它的默认值是 Propagation.REQUIRED。
  • readOnly: 指定事务是否为只读,默认值是 false。
  • isolation: 指定事务的隔离级别,默认值是 Isolation.DEFAULT,即数据库设定的隔离级别。
  • timeout:事务超时时间,默认为数据库设定的时间。
  • rollbackFor:设定要回滚事务的异常类,当捕获到这些异常时回滚,否则不回滚。
  • rollbackForClassName:设定要回滚事务的异常类名称,当捕获到这些异常时回滚,否则不回滚。
  • noRollbackFor:设定不回滚事务的异常类,当捕获到这些异常时不回滚。
  • noRollbackForClassName:设定不回滚事务的异常类名称,当捕获到这些异常时不回滚。
事务传播方式 Propagation
传播方式备注
REQUIRED当前有事务时沿用现有事务,不存在的时候新建一个事务,是默认传播方式。
SUPPORTS当前有事务时沿用现有事务,没有的时候不使用事务。
MANDATORY当前有事务时沿用现有事务,不存在时抛出异常。
REQUIRES_NEW创建新事务,若存在原有事务则挂起原事务。
NOT_SUPPORTED不使用事务,若存在原有事务则挂起原事务。
NEVER不使用事务,若存在原有事务则抛出异常。
NESTED开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务, 嵌套事务开始执行时, 它将取得一个 savepoint。 如果这个嵌套事务失败, 我们将回滚到此 savepoint。嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。
事务隔离级别 Isolation
隔离级别中文名称备注
READ_UNCOMMITTED读未提交最低的隔离级别,一个事务可以读取另一个事务未提交的数据。可能会导致脏读、幻读或不可重复读。
READ_COMMITTED读已提交一个事务只能读取已经提交的数据,但是在同一事务中,多次读取同一数据可能会得到不同的结果。
REPEATABLE_READ可重复读一个事务在同一数据上进行多次读取时,可以得到相同的结果,但是在同一事务中,其他事务插入的数据对该事务不可见。
SERIALIZABLE串行化最高的隔离级别,所有事务串行执行,保证数据的一致性和完整性。

代理类

Spring实例化bean时生成事务增强的代理类,如下图的例子,SimpleController里的@Autowired SimpleService1 simpleService注入bean不是原始的类实例,而是一个Spring实例化bean时使用Cglib生成代理类,本例里是
SimpleServiceA$$EnhancerBySpringCGLIB$$1577407e。这个代理类继承自SimpleServiceA,它的作用是向类增加功能拦截器进行链式处理,对事务注解来说就是添加一个TransactionInterceptor增加事务的处理。
在这里插入图片描述

这个代理类编译或打包后是搜索不到的,在Spring启动后动态生成,在Spring应用启动运行时可通过arthas或jad等工具反编译得到。

从这个类的代码可以看到代理类继承原类SimpleServiceA,代理类的updateA()对原始updateA()方法进行拦截。

代理类代码:

public class SimpleServiceA$$EnhancerBySpringCGLIB$$22b9f492
extends SimpleServiceA
implements SpringProxy,
Advised,
Factory {private boolean CGLIB$BOUND;public static Object CGLIB$FACTORY_DATA;private static final ThreadLocal CGLIB$THREAD_CALLBACKS;private static final Callback[] CGLIB$STATIC_CALLBACKS;private MethodInterceptor CGLIB$CALLBACK_0;private MethodInterceptor CGLIB$CALLBACK_1;private NoOp CGLIB$CALLBACK_2;private Dispatcher CGLIB$CALLBACK_3;private Dispatcher CGLIB$CALLBACK_4;private MethodInterceptor CGLIB$CALLBACK_5;private MethodInterceptor CGLIB$CALLBACK_6;private static Object CGLIB$CALLBACK_FILTER;private static final Method CGLIB$updateA$0$Method;private static final MethodProxy CGLIB$updateA$0$Proxy;private static final Object[] CGLIB$emptyArgs;private static final Method CGLIB$equals$1$Method;private static final MethodProxy CGLIB$equals$1$Proxy;private static final Method CGLIB$toString$2$Method;private static final MethodProxy CGLIB$toString$2$Proxy;private static final Method CGLIB$hashCode$3$Method;private static final MethodProxy CGLIB$hashCode$3$Proxy;private static final Method CGLIB$clone$4$Method;private static final MethodProxy CGLIB$clone$4$Proxy;static {SimpleServiceA$$EnhancerBySpringCGLIB$$22b9f492.CGLIB$STATICHOOK144();SimpleServiceA$$EnhancerBySpringCGLIB$$22b9f492.CGLIB$STATICHOOK143();}static void CGLIB$STATICHOOK144() {try {return;}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}static void CGLIB$STATICHOOK143() {CGLIB$THREAD_CALLBACKS = new ThreadLocal();CGLIB$emptyArgs = new Object[0];Class<?> clazz = Class.forName("cn.massivestars.service.impl.SimpleServiceA$$EnhancerBySpringCGLIB$$22b9f492");Class<?> clazz2 = Class.forName("java.lang.Object");Method[] methodArray = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, clazz2.getDeclaredMethods());CGLIB$equals$1$Method = methodArray[0];CGLIB$equals$1$Proxy = MethodProxy.create(clazz2, clazz, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");CGLIB$toString$2$Method = methodArray[1];CGLIB$toString$2$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");CGLIB$hashCode$3$Method = methodArray[2];CGLIB$hashCode$3$Proxy = MethodProxy.create(clazz2, clazz, "()I", "hashCode", "CGLIB$hashCode$3");CGLIB$clone$4$Method = methodArray[3];CGLIB$clone$4$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");clazz2 = Class.forName("cn.massivestars.service.impl.SimpleServiceA");//原始方法CGLIB$updateA$0$Method = ReflectUtils.findMethods(new String[]{"updateA", "()V"}, clazz2.getDeclaredMethods())[0];//代理方法CGLIB$updateA$0$Proxy = MethodProxy.create(clazz2, clazz, "()V", "updateA", "CGLIB$updateA$0");}}//代理方法和原始方法不一样,作了功能增强public final void updateA() throws Exception {try {MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;if (methodInterceptor == null) {SimpleServiceA$$EnhancerBySpringCGLIB$$22b9f492.CGLIB$BIND_CALLBACKS(this);methodInterceptor = this.CGLIB$CALLBACK_0;}if (methodInterceptor != null) {//使用代理方法对原始方法updateA()进行了功能增强Object object = methodInterceptor.intercept(this, CGLIB$updateA$0$Method, CGLIB$emptyArgs, CGLIB$updateA$0$Proxy);return;}//没有功能增强时使用原始方法super.updateA();return;}catch (Error | Exception | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}//省略代码……
}

代理类的生成

Spring在初始化bean实例的时候过检查一系列条件来确定是否需要对 Bean 进行代理,比如对有@Transactional注解的bean生成额外的增强的代理对象。由于篇幅问题下面的代码分析忽略Spring对一般bean初始化的过程,从生成bean的代理对象开始,即AbstractAutoProxyCreator#postProcessAfterInitialization()方法开始分析,可以跟着这个调用栈跟踪代理对象的生成。

在这里插入图片描述

spring bean功能自动代理部分:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {//开始包裹成代理类return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (beanName != null && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}//1、查找需要生成的功能增强Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);//2、创建代理Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}//3、创建类代理工厂ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}//4、构建增强Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);for (Advisor advisor : advisors) {proxyFactory.addAdvisor(advisor);}proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}//5、使用代理工厂创建代理return proxyFactory.getProxy(getProxyClassLoader());}}

代理工厂部分:

public class ProxyFactory extends ProxyCreatorSupport {public Object getProxy(ClassLoader classLoader) {//6、创建aop代理//7、返回代理对象return createAopProxy().getProxy(classLoader);}protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}//6.1 使用aop工厂创建aop代理return getAopProxyFactory().createAopProxy(this);}}public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {//6.2 创建aop代理public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}//创建cglib aop代理对象return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}}

cglib代理对象部分:

class ObjenesisCglibAopProxy extends CglibAopProxy {public ObjenesisCglibAopProxy(AdvisedSupport config) {super(config);}//7.1 返回增强的代理对象public Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());}try {Class<?> rootClass = this.advised.getTargetClass();Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");//省略代码……//创建增强器Enhancer enhancer = createEnhancer();if (classLoader != null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader &&((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}//配置增强器enhancer.setSuperclass(proxySuperClass);enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));Callback[] callbacks = getCallbacks(rootClass);Class<?>[] types = new Class<?>[callbacks.length];for (int x = 0; x < types.length; x++) {types[x] = callbacks[x].getClass();}// fixedInterceptorMap only populated at this point, after getCallbacks call aboveenhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));enhancer.setCallbackTypes(types);//创建代理类并实例化return createProxyClassAndInstance(enhancer, callbacks);}//省略代码...}protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {Class<?> proxyClass = enhancer.createClass();Object proxyInstance = null;if (objenesis.isWorthTrying()) {try {//创建对象,objenesis创建对象时可以不调用类的构造函数proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());}catch (Throwable ex) {logger.debug("Unable to instantiate proxy using Objenesis, " +"falling back to regular proxy construction", ex);}}//省略代码……((Factory) proxyInstance).setCallbacks(callbacks);return proxyInstance;}}

由于篇幅问题,对spring aop生成代理对象的内容这里只作简略介绍。

代理类责任链模式处理

Spring的bean可以有多个功能增强,@Transactional事务处理是其中一种,还有@Cacheable缓存、@Async异步执行和@Retryable重试等;处理拥有多个功能增强的代理类,Spring使用了一种叫责任链的设计模式。

下面是有@Transactional@Cacheable@Retryable三个功能增强的责任链:

在这里插入图片描述

下图为责任链链式处理的调用调用栈:

在这里插入图片描述


从代理对象到业务方法的过程

从代理对象开始是如何执行到事务拦截器的呢?从上面的代理类代码可以看到调用代理类的方法时,在有功能增强时实际调用的是MethodInterceptorintercept(..)方法,MethodInterceptor实现类是DynamicAdvisedInterceptor,在intercept(..)里,获取功能增强责任链,如果责任链不为空,创建CglibMethodInvocation对象进行处理责任链。

从代理类到业务方法的时序图

在这里插入图片描述

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Class<?> targetClass = null;Object target = null;try {if (this.advised.exposeProxy) {oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}target = getTarget();if (target != null) {targetClass = target.getClass();}//1、获取功能增强责任链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 {//2、责任链不为空retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal = processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target != null) {releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}}//省略代码……}
}private static class CglibMethodInvocation extends ReflectiveMethodInvocation {//3、处理责任链public Object proceed() throws Throwable {if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {//如果责任链已处理完成,调用业务方法return invokeJoinpoint();}//处理责任链的下一个功能增强Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {return proceed();}}else {//调用具体的拦截器return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}
}

下面是一个有@Cacheable、@Retryable和@Transactional注解的调用栈,很清晰的展示代理对象功能增强的调用过程:

cn.massivestars.service.SimpleServiceA.updateA(SimpleServiceA.java:33)
cn.massivestars.service.SimpleServiceA$$FastClassBySpringCGLIB$$6479dd5.invoke(<generated>)
org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:52)
org.springframework.cache.interceptor.CacheAspectSupport.invokeOperation(CacheAspectSupport.java:345)
org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:414)
org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:327)
org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:74)
org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:276)
org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:157)
org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:101)
org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:118)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
cn.massivestars.service.SimpleServiceA$$EnhancerBySpringCGLIB$$3b7e878d.updateA(<generated>)
cn.massivestars.controller.SimpleController.update(SimpleController.java:28)

事务处理的核心方法

事务的处理和我们自己手写的类似,使用try catch代码块包裹业务方法,在业务方法前开启事务,捕获异常时回滚事务,正常运行时最后提交事务。

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {//事务关键代码//这个方法继承自TransactionAspectSupport,代码在TransactionAspectSupportprotected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)throws Throwable {final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);final PlatformTransactionManager tm = determineTransactionManager(txAttr);          //取事务管理器final String joinpointIdentification = methodIdentification(method, targetClass);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {			//如果必要,创建事务TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null;try {//责任链的下一个拦截处理器,在最后一个拦截器处理完后就是业务代码retVal = invocation.proceedWithInvocation();   }catch (Throwable ex) {//出现异常回滚事务completeTransactionAfterThrowing(txInfo, ex);  throw ex;}finally {//还原为原来的事务信息txInfocleanupTransactionInfo(txInfo);}//提交事务commitTransactionAfterReturning(txInfo);return retVal;}//省略代码……}}

有关的类和组件都已经介绍完毕,下面看看事务管理器处理事务的开始、提交和回滚是怎样实现。


开始事务

开始事务流程如下:

  1. 创建一个事务对象DataSourceTransactionObject,其名称为transaction,将事务对象关联线程绑定的数据库连接(ConnectionHolder),如果线程没有绑定的连接那么原来就是没有存在事务,该事务对象状态为新。
  2. 根据事务对象transaction判断是不是已存在事务,根据原来是否已经存在事务作2种不同的处理方式。

存在事务,根据事务的传播方式作不同处理:

  • PROPAGATION_NEVER:抛出异常。
  • PROPAGATION_NOT_SUPPORTED:不作事务处理。
  • PROPAGATION_REQUIRES_NEW:使用新的数据库连接,开启新事务B,将B的事务信息和状态绑定到线程,同时挂起原来的事务A,在新事务B完成后线程绑定的事务信息恢复为原事务A。
  • PROPAGATION_NESTED:开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务, 嵌套事务开始执行时,它将取得一个 savepoint。如果这个嵌套事务失败, 将回滚到此 savepoint。嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。

不存在事务,根据事务的传播方式作不同处理::

  • PROPAGATION_MANDATORY,抛出异常,事务拦截器捕抓异常后回滚事务,结束事务处理。
  • PROPAGATION_REQUIRED | PROPAGATION_REQUIRES_NEW | PROPAGATION_NESTED:从数据源获取连接,开启事务,将事务信息和状态绑定到线程。
  • 其它事务传播方式:创建空事务对象,不真正去处理事务,只是将事务信息和状态绑定到线程。
  1. 事务开启完成后配制事务信息TransactionInfo txInfo,将当前方法事务信息绑定到线程并保留原事务信息以便方法嵌套调用的时候可以恢复。

开始事务源码(事务拦截器部分):

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor {protected TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) {//如果事务有名称,将txAttr替换成有事务名称的DelegatingTransactionAttribute实例(相比原来的类多了事务名称)if (txAttr != null && txAttr.getName() == null) {txAttr = new DelegatingTransactionAttribute(txAttr) {@Overridepublic String getName() {return joinpointIdentification;}};}TransactionStatus status = null;if (txAttr != null) {if (tm != null) {//如果事务管理器不为null,开启事务status = tm.getTransaction(txAttr);}}//配制事务信息,事务信息txInfo绑定至当前线程return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);}protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);if (txAttr != null) {txInfo.newTransactionStatus(status);}// 即使在这里没有创建新的事务,始终将 TransactionInfo 绑定到线程。// 这确保了即使没有由此切面创建事务,TransactionInfo 堆栈也将被正确管理。txInfo.bindToThread();return txInfo;}protected final class TransactionInfo {private void bindToThread() {//绑定当前方法事务信息,保留原来事务信息以便当前方法事务结束后恢复this.oldTransactionInfo = transactionInfoHolder.get();transactionInfoHolder.set(this);}}//省略代码...
}

开始事务源码(事务管理器部分):

public class DataSourceTransactionManager extends AbstractPlatformTransactionManagerimplements ResourceTransactionManager, InitializingBean {//数据源private DataSource dataSource;//此方法继承自AbstractPlatformTransactionManager,代码在AbstractPlatformTransactionManagerpublic final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {//创建一个新的事务对象transaction//如果线程已存在事务,事务对象transaction使用原有的连接Object transaction = doGetTransaction();if (definition == null) {definition = new DefaultTransactionDefinition();}if (isExistingTransaction(transaction)) {//存在事务,根据事务的传播方式作不同处理return handleExistingTransaction(definition, transaction, debugEnabled);}//省略代码...//以下代码为不存在事务时的处理if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {//如果事务传播方式为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);DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);//真正开始事务doBegin(transaction, definition);//同步事务信息prepareSynchronization(status, definition);return status;}catch (RuntimeException ex) {resume(null, suspendedResources);throw ex;}catch (Error err) {resume(null, suspendedResources);throw err;}}else {//创建空事务对象,不真正去处理事务,只是将事务信息和状态绑定到线程boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);}}protected Object doGetTransaction() {DataSourceTransactionObject txObject = new DataSourceTransactionObject();txObject.setSavepointAllowed(isNestedTransactionAllowed());ConnectionHolder conHolder =(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);txObject.setConnectionHolder(conHolder, false);  //将事务对象内的数据库连接设置为线程绑定的那个return txObject;}protected void doBegin(Object transaction, TransactionDefinition definition) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;Connection con = null;try {if (txObject.getConnectionHolder() == null ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {//原来不存在事务,从数据源获取连接	Connection newCon = this.dataSource.getConnection();txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}txObject.getConnectionHolder().setSynchronizedWithTransaction(true);con = txObject.getConnectionHolder().getConnection();//设置事务隔离级别Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);//如果设置了事务自动提交,改为手动提交if (con.getAutoCommit()) {txObject.setMustRestoreAutoCommit(true);con.setAutoCommit(false);}txObject.getConnectionHolder().setTransactionActive(true);//设置事务超时时间int timeout = determineTimeout(definition);if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}//将数据库连接绑定到线程if (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());}}catch (Throwable ex) {//如果出现异常,归还还数据库连接,if (txObject.isNewConnectionHolder()) {DataSourceUtils.releaseConnection(con, this.dataSource);txObject.setConnectionHolder(null, false);}throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}}	
}

挂起事务

嵌套事务是指在一个事务内部开启了另一个事务。当一个事务内部开启了另一个事务时,外部事务会暂时挂起,直到内部事务执行完成。在源码中多次出现suspend()方法挂起原事务,挂起事务的目的在于:

支持嵌套事务:在某些事务传播行为下,比如PROPAGATION_REQUIRES_NEW和PROPAGATION_NESTED,Spring需要支持嵌套事务。当这些传播行为发生时,当前正在执行的事务可能需要被挂起,以便开始一个新的事务。挂起原事务可以暂时中断当前事务的执行,让新的事务能够开始执行。

保存原事务的状态:挂起原事务会保存原事务的状态信息,以便在新事务执行完毕后能够正确地恢复原事务的状态。这对于事务管理的一致性和可靠性非常重要。

处理事务异常:在执行新事务的过程中,可能会发生异常。挂起原事务可以确保异常的发生不会影响到原事务的状态,保证事务的正确回滚和异常处理。

挂起事务的有关源码:

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager {//该方法继承自父类AbstractPlatformTransactionManager,代码在父类AbstractPlatformTransactionManagerprotected final SuspendedResourcesHolder suspend(Object transaction) throws TransactionException {if (TransactionSynchronizationManager.isSynchronizationActive()) {List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();try {Object suspendedResources = null;   //挂起的数据库连接持有者           if (transaction != null) {suspendedResources = doSuspend(transaction); //挂起事务}//将线程绑定的原事务信息清除,返回原事务信息作为挂起事务信息String name = TransactionSynchronizationManager.getCurrentTransactionName();TransactionSynchronizationManager.setCurrentTransactionName(null);boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();TransactionSynchronizationManager.setActualTransactionActive(false);return new SuspendedResourcesHolder(suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);}catch (RuntimeException ex) {//还原事务管理器注册的TransactionSynchronization对象doResumeSynchronization(suspendedSynchronizations);throw ex;}catch (Error err) {//还原事务管理器注册的TransactionSynchronization对象doResumeSynchronization(suspendedSynchronizations);throw err;}}else if (transaction != null) {// Transaction active but no synchronization active.Object suspendedResources = doSuspend(transaction);return new SuspendedResourcesHolder(suspendedResources);}else {// Neither transaction nor synchronization active.return null;}}//将事务对象的数据库连接设置为空,将线程绑定的数据库连接解绑protected Object doSuspend(Object transaction) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;txObject.setConnectionHolder(null);ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.unbindResource(this.dataSource);return conHolder;}}

恢复事务

上面介绍了事务的挂起,既然有挂起就有恢复,挂起事务是和恢复事务配套使用的;在事务的提交processCommit()和回滚processRollback()的finally代码块都会执行cleanupAfterCompletion()方法,这个方法里,如果存在挂起的事务信息时,会恢复挂起的事务。

恢复事务的有关源码:

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager {implements ResourceTransactionManager, InitializingBean {private void cleanupAfterCompletion(DefaultTransactionStatus status) {status.setCompleted();if (status.isNewSynchronization()) {TransactionSynchronizationManager.clear();}if (status.isNewTransaction()) {doCleanupAfterCompletion(status.getTransaction());}if (status.getSuspendedResources() != null) {//恢复事务resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());}}protected final void resume(Object transaction, SuspendedResourcesHolder resourcesHolder)throws TransactionException {if (resourcesHolder != null) {Object suspendedResources = resourcesHolder.suspendedResources;if (suspendedResources != null) {//恢复旧连接,绑定至线程doResume(transaction, suspendedResources);}//恢复事务状态和信息List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;if (suspendedSynchronizations != null) {TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);doResumeSynchronization(suspendedSynchronizations);}}}
}public class DataSourceTransactionManager extends AbstractPlatformTransactionManagerimplements ResourceTransactionManager, InitializingBean {protected void doResume(Object transaction, Object suspendedResources) {ConnectionHolder conHolder = (ConnectionHolder) suspendedResources;//重新将原数据库连接绑定到线程TransactionSynchronizationManager.bindResource(this.dataSource, conHolder);}}

下面来看看事务挂起和恢复的详细过程。假设有代理对象A和代理对象B:

  • 代理对象A的注解为@Transactional
  • 代理对象B的注解为@Transactional(propagation = Propagation.REQUIRES_NEW)

当调用代理对象A的方法a()时,方法a()嵌套调用了代理对象B的方法b(),这时候会产生事务的挂起和恢复。

挂起和恢复事务的时序图:

在这里插入图片描述


提交事务

Spring提交通过事务管理器提交事务,通过事务对象txObject内含的数据库连接提交事务,在提交事务完成后将做下列操作:

  1. 事务状态设置为已完成。
  2. 解绑线程的数据库连接。
  3. 清除线程绑定的事务状态和信息。
  4. 重置为旧事务信息TransactionInfo(方法嵌套调用的时候)。
  5. 如果事务状态为新事务,将数据库连接归还连接池。

事务提交调用栈

在这里插入图片描述

源码:

//事务拦截器
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor//该方法继承子类TransactionAspectSupportprotected void commitTransactionAfterReturning(TransactionInfo txInfo) {if (txInfo != null && txInfo.hasTransaction()) {//通过事务管理器提交事务txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}}protected void cleanupTransactionInfo(TransactionInfo txInfo) {if (txInfo != null) {//恢复为旧的事务信息(方法嵌套调用会还原为调用栈中上一个方法的事务信息)txInfo.restoreThreadLocalStatus();}}protected final class TransactionInfo {private void restoreThreadLocalStatus() {//恢复为旧的事务信息(方法嵌套调用会还原为调用栈中上一个方法的事务信息)transactionInfoHolder.set(this.oldTransactionInfo);}}//省略代码……}//事务管理器
public class DataSourceTransactionManager extends AbstractPlatformTransactionManagerpublic 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()) {processRollback(defStatus);return;}if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {processRollback(defStatus);if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");}return;}processCommit(defStatus);  //处理事务提交}//该方法继承子类AbstractPlatformTransactionManagerprivate void processCommit(DefaultTransactionStatus status) throws TransactionException {try {boolean beforeCompletionInvoked = false;try {prepareForCommit(status);//调用业务方法里注册TransactionSynchronization对象的beforeCommit()方法triggerBeforeCommit(status);//调用业务方法里注册TransactionSynchronization对象的beforeCompletion()方法triggerBeforeCompletion(status);   beforeCompletionInvoked = true;boolean globalRollbackOnly = false;if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {globalRollbackOnly = status.isGlobalRollbackOnly();}//释放在当前事务中之前定义的一个保存点。if (status.hasSavepoint()) {status.releaseHeldSavepoint();}else if (status.isNewTransaction()) {//如果是事务状态为新事务才提交(方法嵌套调用的话是在最外层的方法)doCommit(status);}// Throw UnexpectedRollbackException if we have a global rollback-only// marker but still didn't get a corresponding exception from commit.if (globalRollbackOnly) {throw new UnexpectedRollbackException("Transaction silently rolled back because it has been marked as rollback-only");}}catch (UnexpectedRollbackException ex) {//调用业务方法里注册TransactionSynchronization对象的afterCompletion()方法triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);throw ex;}catch (TransactionException ex) {// can only be caused by doCommitif (isRollbackOnCommitFailure()) {doRollbackOnCommitException(status, ex);}else {//调用业务方法里注册TransactionSynchronization对象的afterCompletion()方法triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);}throw ex;}catch (RuntimeException ex) {if (!beforeCompletionInvoked) {//调用业务方法里注册TransactionSynchronization对象的beforeCompletion()方法triggerBeforeCompletion(status);}doRollbackOnCommitException(status, ex);throw ex;}catch (Error err) {if (!beforeCompletionInvoked) {//调用业务方法里注册TransactionSynchronization对象的beforeCompletion()方法triggerBeforeCompletion(status);}doRollbackOnCommitException(status, err);throw err;}try {//调用业务方法里注册TransactionSynchronization对象的afterCommit()方法triggerAfterCommit(status);}finally {//调用业务方法里注册TransactionSynchronization对象的afterCommit()方法triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);}}finally {cleanupAfterCompletion(status);}}protected void doCommit(DefaultTransactionStatus status) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();Connection con = txObject.getConnectionHolder().getConnection();try {con.commit();  //使用数据库连接提交事务}catch (SQLException ex) {throw new TransactionSystemException("Could not commit JDBC transaction", ex);}}private void cleanupAfterCompletion(DefaultTransactionStatus status) {status.setCompleted();   //事务状态设置为已完成if (status.isNewSynchronization()) {TransactionSynchronizationManager.clear();}if (status.isNewTransaction()) {doCleanupAfterCompletion(status.getTransaction());}if (status.getSuspendedResources() != null) {//如果是嵌套方法,恢复原来挂起的事务resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());}}protected void doCleanupAfterCompletion(Object transaction) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;//解绑线程已绑定的数据库连接if (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.unbindResource(this.dataSource);}//重置数据库连接的设置Connection con = txObject.getConnectionHolder().getConnection();try {if (txObject.isMustRestoreAutoCommit()) {con.setAutoCommit(true);}DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());}catch (Throwable ex) {logger.debug("Could not reset JDBC Connection after transaction", ex);}if (txObject.isNewConnectionHolder()) {//返还数据库连接DataSourceUtils.releaseConnection(con, this.dataSource);}txObject.getConnectionHolder().clear();}}

回滚事务

在业务逻辑执行过程中出现异常时,事务拦截器会捕获异常,并根据事务注解的配置判断是否符合回滚的条件,若符合则会回滚事务。

    protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {if (txInfo != null && txInfo.hasTransaction()) {if (txInfo.transactionAttribute.rollbackOn(ex)) {  //根据规则判断是否要回滚try {//使用事务管理器回滚事务txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException ex2) {throw ex2;}catch (Error err) {throw err;}}else {//使用事务管理器提交事务try {txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException ex2) {throw ex2;}catch (Error err) {logger.error("Application exception overridden by commit error", ex);throw err;}}}}private void processRollback(DefaultTransactionStatus status) {try {try {triggerBeforeCompletion(status);if (status.hasSavepoint()) {status.rollbackToHeldSavepoint();}else if (status.isNewTransaction()) {//如果事务状态为新事务才回滚(比如嵌套调用的最外层方法)doRollback(status);}else if (status.hasTransaction()) {if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {doSetRollbackOnly(status);}}}catch (RuntimeException ex) {triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);throw ex;}catch (Error err) {triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);throw err;}triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);}finally {cleanupAfterCompletion(status);}}protected void doRollback(DefaultTransactionStatus status) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();Connection con = txObject.getConnectionHolder().getConnection();try {con.rollback();  //使用数据库连接回滚事务}catch (SQLException ex) {throw new TransactionSystemException("Could not roll back JDBC transaction", ex);}
}

回滚规则的判断

判断当前异常是否符合注解@Transactional设置的rollbackFor和noRollbackFor,只有符合条件的异常才回滚事务。

public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute {public boolean rollbackOn(Throwable ex) {RollbackRuleAttribute winner = null;int deepest = Integer.MAX_VALUE;//是否命中回滚规则if (this.rollbackRules != null) {for (RollbackRuleAttribute rule : this.rollbackRules) {int depth = rule.getDepth(ex);if (depth >= 0 && depth < deepest) {deepest = depth;winner = rule;}}}//如果没有命中回滚规则,使用父类的默认回滚规则if (winner == null) {return super.rollbackOn(ex);}//不是非回滚规则return !(winner instanceof NoRollbackRuleAttribute);}//该方法继承自DefaultTransactionAttribute,代码在DefaultTransactionAttributepublic boolean rollbackOn(Throwable ex) {//默认回滚的异常类型:RuntimeException和Errorreturn (ex instanceof RuntimeException || ex instanceof Error);}
}

从源码可知默认回滚的异常类型为RuntimeExceptionError,当出现IOExceptionNoClassDefFoundException之类的非RuntimeException异常时,默认情况事务并不会回滚,这可能会导致和我们预期的不一致。大多数情况下,推荐事务注解配置rollbackFor的回滚异常为Exception.class。

@Transactional(rollbackFor = Exception.class)

事务完成后清理的方法

Spring在事务提交或回滚后使用cleanupAfterCompletion()方法在事务完成后执行一些必要的清理操作,以确保下一个事务可以从一个干净的状态开始。

//事务管理器
public class DataSourceTransactionManager extends AbstractPlatformTransactionManagerprivate void cleanupAfterCompletion(DefaultTransactionStatus status) {status.setCompleted();   //事务状态设置为已完成if (status.isNewSynchronization()) {TransactionSynchronizationManager.clear();}if (status.isNewTransaction()) {doCleanupAfterCompletion(status.getTransaction());}if (status.getSuspendedResources() != null) {//如果是嵌套方法,恢复原来挂起的事务resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());}}protected void doCleanupAfterCompletion(Object transaction) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;//解绑线程已绑定的数据库连接if (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.unbindResource(this.dataSource);}//重置数据库连接的设置Connection con = txObject.getConnectionHolder().getConnection();try {if (txObject.isMustRestoreAutoCommit()) {con.setAutoCommit(true);}DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());}catch (Throwable ex) {logger.debug("Could not reset JDBC Connection after transaction", ex);}if (txObject.isNewConnectionHolder()) {//返还数据库连接DataSourceUtils.releaseConnection(con, this.dataSource);}txObject.getConnectionHolder().clear();}}

事务同步管理器TransactionSynchronizationManager

Spring 的事务同步管理器 TransactionSynchronizationManager 是 Spring 框架中用于管理事务同步的工具类。它使用ThreadLocal存储信息,允许在事务的不同阶段注册回调,以执行特定的操作。主要作用包括以下几个方面:

事务同步回调注册: TransactionSynchronizationManager允许在事务的不同阶段注册回调方法,如在事务完成时、事务回滚时、事务提交前等。开发者可以通过该工具类注册相应的回调方法来执行特定的操作,例如在事务提交后清理资源、发送消息等。

线程绑定: TransactionSynchronizationManager是基于线程的,它允许将事务同步回调与当前线程进行绑定。这意味着只有与事务关联的线程才能触发事务同步回调,从而保证了线程安全性。

支持多个同步回调: TransactionSynchronizationManager支持注册多个事务同步回调,这些回调可以按照注册的顺序执行。这样可以方便地实现多个模块间的协作,每个模块都可以在适当的时候执行自己的逻辑。

提供事务状态管理: TransactionSynchronizationManager还提供了方法来获取当前事务的状态,如事务是否处于激活状态、是否已经完成、是否已经回滚等。这样可以帮助开发者根据当前事务的状态执行相应的操作。

与事务管理器配合使用: TransactionSynchronizationManager 通常与事务管理器(如 PlatformTransactionManager)配合使用,以确保事务同步回调的正确执行。它可以在事务的开始、提交、回滚等关键节点触发相应的回调,并在合适的时机执行事务同步逻辑。

线程绑定的信息

public abstract class TransactionSynchronizationManager {//数据库连接持有者connectionHolderprivate static final ThreadLocal<Map<Object, Object>> resources =new NamedThreadLocal<Map<Object, Object>>("Transactional resources");//在业务方法里通过TransactionSynchronizationManager#registerSynchronization注册的同步执行方法private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");//业务名称private static final ThreadLocal<String> currentTransactionName =new NamedThreadLocal<String>("Current transaction name");//事务是否只读private static final ThreadLocal<Boolean> currentTransactionReadOnly =new NamedThreadLocal<Boolean>("Current transaction read-only status");//业务隔离级别private static final ThreadLocal<Integer> currentTransactionIsolationLevel =new NamedThreadLocal<Integer>("Current transaction isolation level");//事务是否激活private static final ThreadLocal<Boolean> actualTransactionActive =new NamedThreadLocal<Boolean>("Actual transaction active");}

绑定和解绑资源

这里的资源是指数据库连接持有者。

	public static void bindResource(Object key, Object value) throws IllegalStateException {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Assert.notNull(value, "Value must not be null");Map<Object, Object> map = resources.get();//如果绑定的map对象为空,初始化它if (map == null) {map = new HashMap<Object, Object>();resources.set(map);}Object oldValue = map.put(actualKey, value);// Transparently suppress a ResourceHolder that was marked as void...if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {oldValue = null;}if (oldValue != null) {throw new IllegalStateException("Already value [" + oldValue + "] for key [" +actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");}}public static Object unbindResource(Object key) throws IllegalStateException {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Object value = doUnbindResource(actualKey);if (value == null) {throw new IllegalStateException("No value for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");}return value;}private static Object doUnbindResource(Object actualKey) {Map<Object, Object> map = resources.get();if (map == null) {return null;}Object value = map.remove(actualKey);if (map.isEmpty()) {resources.remove();  //清除线程绑定的数据库连接}//连接为无效时将它设置为空if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {value = null;}return value;}

事务失效

在Spring出现事务失效最常见的是因为在同一个类内部的方法之间的调用,在上面已经分析过只有在使用代理对象调用业务方法才会有对应的功能增强,同一个类内方法间用的是this对象,不具备事务增强。

下面是一个失效例子:

@Service
public class Caller {@AutowiredSimpleService simpleService;public void call() {simpleService.updateA();}
}@Service
public class SimpleService {public void updateA() {//这里调用updateB()等同于this.updateB(),使用的是this对象,不具备事务增强,事务失效updateB();}@Transactional(rollbackFor = Exception.class)public void updateB() {String sql = "update article set title = 'Today is a good day!' where id = 1";jdbcTemplate.update(sql);}
}

小结

本文简述了Spring注解式事务@Transactional的原理,分析了关键代码,了解源码的实现能帮助我们更好的使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/519931.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

亚信安慧AntDB:企业数据管理的明日之星

在信息科技飞速发展的时代&#xff0c;亚信科技AntDB团队提出了一项颠覆性的“超融合”理念&#xff0c;旨在满足企业日益增长的复杂混合负载和多样化数据类型的业务需求。这一创新性框架的核心思想在于融合多引擎和多能力&#xff0c;充分发挥分布式数据库引擎的架构优势&…

《操作系统真相还原》读书笔记一:环境搭建 32位centos6.3+bochs

下载32位的centos6.3centos6.3 https://archive.kernel.org/centos-vault/6.3/isos/i386/ 在virtualbox中安装centos6.3 1、系统运维中常用的Linux操作系统是红帽Linux或者CentOS。 从官方网站下载CentOS 6.3镜像光盘。 2、运行虚拟机&#xff0c;在选择界面选择"Inst…

如何将中科方德桌面操作系统加入Windows域

往期文章&#xff1a;自定义SSH客户端连接时的显示信息 | 统信UOS | 麒麟KYLINOS Hello&#xff0c;大家好啊&#xff0c;今天我非常高兴地给大家带来一篇关于如何将中科方德桌面操作系统加入Windows域的教程文章。对于使用中科方德桌面操作系统的用户来说&#xff0c;将其加入…

【设计模式 05】原型模式

有的时候&#xff0c;我们创建对象&#xff0c;需要耗费大量时间在一些资源型操作上&#xff0c;这个时候&#xff0c;我们就可以先创建出一个模板&#xff0c;然后每次创建的时候直接从模板复制即可&#xff0c;不用反复进行耗时的资源型操作。 python代码&#xff1a; impo…

一命通关前缀和

前缀和 简介 先来简单看一个场景。现在有一个公交车&#xff0c;第一站上了4个人&#xff0c;第二站上了7个人&#xff0c;第三站上了1个人&#xff0c;第四站上了5个人&#xff0c;问一共上了多少人&#xff1f; 答案很显而易见&#xff0c;只需要遍历这个数组&#xff0c;把…

使用PHP实现动态代理IP的功能

目录 前言 一、 什么是代理IP 二、动态代理IP的原理 三、使用ProxyCrawl API获取代理IP 安装和配置 发送请求获取代理IP 实现动态代理IP的功能 总结 前言 动态代理IP是一种通过不断切换不同的代理IP来隐藏真实IP地址的技术。在使用网络爬虫、进行数据采集、访问被封IP…

基于 Win Server 2008 复现 IPC$ 漏洞

写在前面 本篇博客演示了使用 winXP&#xff08;配合部分 win10 的命令&#xff09;对 win server 2008 的 IPC$ 漏洞进行内网渗透&#xff0c;原本的实验是要求使用 win server 2003&#xff0c;使用 win server 2003 可以规避掉很多下面存在的问题&#xff0c;建议大家使用 …

k8s 网络概念与策略控制

一、Kubernetes 基本网络模型 Kubernetes 的容器网络模型可以把它归结为约法三章和四大目标。 1、约法三章 约法三章确保了Kubernetes容器网络模型的基本特性&#xff1a; ① 任意两个 pod 之间可以直接通信&#xff1a;在Kubernetes中&#xff0c;每个 Pod 都被分配了一个…

ResponseStatusException

目录 概述&#xff1a; 综合实例&#xff1a; 继承 ResponseStatusException-自定义异常类 继承 ResponseStatusException-自定义响应头信息 继承 ResponseStatusException-定制更多异常处理逻辑 继承 ResponseStatusException-根据异常发生的上下文动态改变 HTTP 状态码…

网络协议栈--应用层--HTTP协议

目录 本节重点理解应用层的作用, 初识HTTP协议 一、应用层二、HTTP协议2.1 认识URL2.2 urlencode和urldecode2.3 HTTP协议格式2.4 HTTP的方法2.4 HTTP的状态码2.5 HTTP常见的Header属性 三、最简单的HTTP服务器3.1 HttpServer.hpp3.2 HttpServer.cc3.3 HttpClient.cc3.4 log.hp…

Allure小白下载安装

1、下载官网地址&#xff1a;https://github.com/allure-framework/allure2/releases 2、下载安装包后需要解压到一个非中文名称路径下 3、配置环境变量 D:\Allure\allure-2.27.0\bin 我的电脑右键选择属性&#xff0c;高级系统设置&#xff0c;环境变量 4、CMD查看安装all…

QGIS3.34官方版本已经不能支持Win7,如果需要在WIN7上使用,请用微云上我打包的

在网上看到有些网友在WIN7上安装官方发布的QGIS安装&#xff0c;会遇到上述问题&#xff0c;而不能正常运行&#xff01; 我打包的QGIS可以在WIN7上正常运行&#xff0c;这个我专门测试过。 详见&#xff1a; 打包了一个QGIS3.34分享给大家 下载地址&#xff1a;文件分享 软…