spring源码篇(八)事务的原理

文章目录

  • 前言
  • 基本操作
    • 验证
  • Spring事务的传播机制
  • 特殊的机制说明
    • NOT_SUPPORTED
    • NESTED
    • SUPPORTS
  • 源码
    • 加载事务自动配置类
      • 要不要加注解:@EnableTransactionManagement
      • 配置类说明
    • EnableTransactionManagement 做了什么
      • AutoProxyRegistrar做了什么
        • 创建的代理类是jdk动态代理还是cglib
      • ProxyTransactionManagementConfiguration做了什么
    • 事务代理过程
    • 如何完成的事务代理
      • 第一次开启事务怎么执行
      • 已存在事务怎么执行
      • 事务挂起恢复
      • rollback

前言

不流于表面,深入理解AOP与事务逻辑的配合完成事务,文章内容有些长,拆了可能影响前后逻辑连贯型,

基本操作

数据库执行事务步骤是这样的:

  1. 开启事务 begin sql commit autocommit = on
  2. sql
  3. commit
  4. rollback

mysql中一个事务的由begin开始,commit结束,在事务中的错误都会回退,而一般情况下都是开启了autocommit=on,使得每个sql都会commit;

验证

  1. 一个方法调用两个insert,两个insert的应是单独的连接对象,或者同一个对象,但connection中的autocommit=true
    public Object sw() {
        Demo demo = new Demo();
        demo.setDbName("sw-ces1");
        demoMapper.insert(demo);
        demo = new Demo();
        demo.setDbName("sw-ces2");
        demoMapper.insert(demo);
        return null;
    }

这个方法调用了两次insert,生成了两个连接实例对象connection,并且auto commit=true如下图:

方法定位:org.mybatis.spring.SqlSessionTemplate#insert(java.lang.String, java.lang.Object)

image-20230424223106266

  1. 在Spring事务中,应是同一个connection对象,保证一些列的数据库操作在同一个事务中完成。

那么,打上注解:@Transactional

    @Transactional
    public Object sw() {
        Demo demo = new Demo();
        demo.setDbName("sw-ces1");
        demoMapper.insert(demo);
        demo = new Demo();
        demo.setDbName("sw-ces2");
        demoMapper.insert(demo);
        return null;
    }

再次查看connection对象,会发现是两个insert的connection对象都是同一个,并且autocommit=false

org.mybatis.spring.SqlSessionTemplate#insert(java.lang.String, java.lang.Object)

image-20230424223206354

那么到这里,spring的事务基本轮廓已经清晰了,通过spring对connection的管理以达到事务的控制。

Spring事务的传播机制

Spring事务的管理,确实是通过connect的管理来实现的,不过这也只是我们片面的理解,Spring事务的能做到的比我们想象中要多一些;下面是spring官方的特性描述:数据访问 (spring.io)

  • 跨不同事务 API(如 Java)的一致编程模型 事务 API (JTA)、JDBC、Hibernate 和 Java Persistence API (JPA)。
  • 支持声明式事务管理。
  • 用于编程事务管理的更简单的 API 而不是复杂的事务 API,例如 JTA。
  • 与 Spring 的数据访问抽象完美集成。

在Spring中,它以枚举定义了7种类型:

  • REQUIRED(默认的):保证有事务注解的的方法及其方法内部调用的方法所使用的connection为同一个,并且在同一个事务中。

  • REQUIRES_NEW:当存在这个类型时,spring会重新创建一个连接并开启新事务。

  • NESTED:嵌套式的传播机制,如果有外层事务,则会嵌套一个事务,但是该事务也在外层事务的作用范围内。

  • SUPPORTS:如果外层没有事务,就不加事务,但是内部事务生效

  • MANDATORY:使用当前事务,如果当前事务不存在,则抛出Exception

  • NOT_SUPPORTED:方法调用链期间,当出现NOT_SUPPORTED时,事务打断不生效,在接下去的调用链中,出现REQUIRED时,又会重新生效。

  • NEVER:非事务方式,如果方法内部有开启事务,会抛异常。

它的使用方式简单的就是在注解@Transactional里标准类型就可以了

@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)

特殊的机制说明

这里通过使用的效果进行说明,后面看源码时,容易理解。

NOT_SUPPORTED

方法调用链期间,当出现NOT_SUPPORTED时,事务打断不生效,在接下去的调用链中,出现REQUIRED时,又会重新生效,

    /**
     * 外层 事务  生效
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void out(){
        Demo demo = new Demo();
        demo.setName("NOT_SUPPORTED外层事务");
        demoMapper.insert(demo);
		// 调用标记NOT_SUPPORTED了的方法
        applicationContext.getBean(DemoService.class).in();
    }

// 中间层 NOT_SUPPORTED 没有事务
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
    public void in() {
        Demo demo = new Demo();
        demo.setName("NOT_SUPPORTED内层事务");
        demoMapper.insert(demo);
        // 调用开启事务的方法
       // applicationContext.getBean(DemoService.class).in2();
        applicationContext.getBean(DemoService.class).in22();
    }

// 下层 事务 生效
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void in2() {
        Demo demo = new Demo();
        demo.setName("NOT_SUPPORTED内层 内层 事务");
        demoMapper.insert(demo);
        int i = 1/0;
    }
// 下层 事务 不生效
    public void in22() {
        Demo demo = new Demo();
        demo.setName("NOT_SUPPORTED内层 内层 事务2");
        demoMapper.insert(demo);
        int i = 1/0;
    }

结果如下两个:

image-20230508221612063

image-20230517220808838

NESTED

嵌套式的传播机制,如果有外层事务,则会嵌套一个事务,但是该事务也在外层事务的作用范围内。

  1. NESTED可以独立回滚事务
  2. NESTED事务方法的异常被外层吃掉,外层事务和NESTED就相互独立,如游戏存档
  3. 如果外层异常,内部的NESTED事务也会回滚
    /**
      外层 事务
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void out2() {
        Demo demo = new Demo();
        demo.setName("NESTED外层事务");
        demoMapper.insert(demo);

        try {
            applicationContext.getBean(DemoService.class).in3();
        } catch (Exception e) {
            System.out.println("NESTED方法异常");
        }
        //        如果,这里报异常,内部的`NESTED`事务也会回滚
        //        int i = 1/0;
    }

    /** 
    	中间层 NESTED 事务
    
     * 1. NESTED 可以独立回滚;如果出现异常,那么这个方法内的所有数据回滚
     * 2. 如果这里是REQUIRED,那么包括外层都会回滚
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
    public void in3() {
        Demo demo = new Demo();
        demo.setName("NESTED内层事务");
        demoMapper.insert(demo);
        applicationContext.getBean(DemoService.class).in4();
    }
// 下层 事务
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void in4() {
        Demo demo = new Demo();
        demo.setName("NESTED内层 内层 事务");
        demoMapper.insert(demo);
        int i = 1/0;
    }

SUPPORTS

SUPPORT如果外层没有事务,则就不加事务,但是内部事务生效,如下,

// 外层 没事务
    public void out3() {
        Demo demo = new Demo();
        demo.setName("SUPPORTS外层事务");
        demoMapper.insert(demo);

        applicationContext.getBean(DemoService.class).in6();
    }
// 中间层 SUPPORTS没事务
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
    public void in6() {
        Demo demo = new Demo();
        demo.setName("SUPPORTS内层事务");
        demoMapper.insert(demo);
        applicationContext.getBean(DemoService.class).in4();
    }

// 下层 开启事务,并且生效
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void in4() {
        Demo demo = new Demo();
        demo.setName("NESTED内层 内层 事务");
        demoMapper.insert(demo);
        int i = 1/0;
    }

源码

加载事务自动配置类

spring中的很多组件都是通过自动配置类来加载的,如果是spring自己的,那么就在spring-boot-autoconfigure下的spring.factories中,我们可以在里面找到下面这个配置类:

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

要不要加注解:@EnableTransactionManagement

其实可以不用的,在@SpringBootApplication里的@EnableAutoConfiguration会去取spring.factories,里面有TransactionAutoConfiguration类,我们看一下它的其中一部分:

    @Configuration(
        proxyBeanMethods = false
    )
    @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
        )
        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() {
            }
        }
    }

如上,它会注入一个EnableTransactionManagementConfiguration配置类,然后扫描到注解@EnableTransactionManagement,所以,可以不用特意加上注解。

配置类说明

TransactionAutoConfiguration配置类头上有加如下的注解:

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({PlatformTransactionManager.class})
@AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class})
@EnableConfigurationProperties({TransactionProperties.class})

@Configuration:被spring识别为配置类的标识,这里大家思考一下,被spring识别为配置类的的标识有哪些注解?

@ConditionalOnClass({PlatformTransactionManager.class}):这个是当存在PlatformTransactionManager类时才进行配置类加载

@AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class}):

这个是在spring加载这些配置类后才进行该配置类的加载,那么,如果你引入spring-data-jdbc的话,就会存在DataSourceTransactionManagerAutoConfiguration这个配置类,同时也看出,它支持:jta,jpa,jdbc,neo4j。

@EnableConfigurationProperties({TransactionProperties.class}):事务配置参数,可以定义spring.transaction.defaultTimeout/rollbackOnCommitFailure属性

然后重点就是EnableTransactionManagement

image-20230521165256022

image-20230521174128186

EnableTransactionManagement 做了什么

这个注解两个重要的属性:

proxyTargetClass:默认值:false;true:表示可以使用CGLIB代理,如果有接口则还是用jdk动态代理,false:使用JDK动态代理

mode: 默认值:PROXY;值为PROXY时表示用JDK动态代理,ASPECTJ表示使用Spring的@Aspect进行切面代理;要注意的是,使用PROXY对同一个类内部的本地调用无法拦截,如果要实现高级的拦截,要使用ASPECTJ

AutoProxyRegistrar做了什么

AutoProxyRegistrar的作用是注册了beanName为internalAutoProxyCreator,类为InfrastructureAdvisorAutoProxyCreator的beanDefinition,该类继承AbstractAdvisorAutoProxyCreator

AbstractAdvisorAutoProxyCreator:这个类在AOP章节提过,他是AOP代理自动创建类,主要做下面几个操作:

  1. 首先在初始化bean后,会调用它的postProcessAfterInitialization方法进行代理类处理
  2. 判断是该bean是否需要被代理
  3. 创建代理对象(这里创建的代理会根据对象进行判断)

AOP代理和事务代理,他们都实现了同一个AbstractAdvisorAutoProxyCreator,然后进行了自定义的实现,用于适配不同场景的功能。

image-20230521182932882

接下来,看一下AutoProxyRegistrar实现,因为它实现ImportBeanDefinitionRegistrar,所以它这里做了注册bean的逻辑操作。

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
    // 获取配置类CglibAutoProxyConfiguration上的注解
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
		for (String annType : annTypes) {
            // 获取注解上的属性
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
            // 这个属性应该只有这里用到,用于判断是否创建代理
			Object mode = candidate.get("mode");
            // 这个属性它对应的是`proxyFactory`里的proxyTargetClass的,表示可以使用cglib代理
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				if (mode == AdviceMode.PROXY) {
// 如果不存在 InfrastructureAdvisorAutoProxyCreator 则注入一个:
// beanName=internalAutoProxyCreator,
// class=InfrastructureAdvisorAutoProxyCreator
// 的beanDefinition
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
                        // 强制使用代理类设置,这里是把`proxyTargetClass`设置到InfrastructureAdvisorAutoProxyCreator
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
		if (!candidateFound && logger.isInfoEnabled()) {
			String name = getClass().getSimpleName();
// 			......
		}
	}

看一下这里:

image-20230521184842385

image-20230521185004962

它这里设置了一个属性proxyTargetClassInfrastructureAdvisorAutoProxyCreator里,internalAutoProxyCreatorInfrastructureAdvisorAutoProxyCreator的beanName,忘记了可以再看下上面代码的注释;

这里.add("proxyTargetClass", Boolean.TRUE);,在这个类中,并没有proxyTargetClass属性,所以这里用了add,这里关系到下面的逻辑,所以这里提一下,其实它并没有实际上的意义。

创建的代理类是jdk动态代理还是cglib

结果:只会是CGLIB代理,不是JDK代理,理由看下面。

注解EnableTransactionManagement中设置了proxyTargetClass = true,表示可以使用CGLIB,看下面创建代理类的代码

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 判断是否需要优化,是否使用cglib代理,是否指定了接口
        // 如果不需要优化,且没有指定要使用cglib代理,而且没有指定接口,就使用JDK代理
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("xxxxx");
			}
            // 判断代理类是否是一个接口,或者是否代理类
            // 如果是则使用JDK代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

这个方法有三个判断(第二个忽略):

  1. 第一个if:判断是否需要优化,是否使用cglib代理,是否指定了接口:首先在注册创建类时,就指定了使用cblib代理(config.isProxyTargetClass()=true),同时这个条件生效时,不进行接口的查找,没有设置过接口对象,即hasNoUserSuppliedProxyInterfaces(config)=false,但这里是或,所以第一个判断进入
  2. 第三个if:判断targetClass是否是一个接口类型,注意,这里的代码时bean初始化后执行的,所以这个targetClass不是一个接口类型,所以targetClass.isInterface()=false,并且我们正要代理事务是吧,所以Proxy.isProxyClass(targetClass)=false,那么第三个if没有进入,直接return new ObjenesisCglibAopProxy(config);

图解:

image-20230523222510837

之前在AOP章节里,有说到过,在spring的自动代理中,如果代理的对象有接口,那么会使用JDK代理,没有的就使用cglib;

而在这里,因为属性proxyTargetClass=true的影响,会走到第三个if判断,而且第三个的if都是false,所以都是cglib代理。

总结:

  1. EnableTransactionManagementConfiguration配置类中配置了两个注解@EnableTransactionManagement并且属性都不同,但只要其中有一个的属性是:proxyTargetClass = true就可以的,为true时,会注册事务代理创建类InfrastructureAdvisorAutoProxyCreator,并将设置proxyTargetClass = true设置进去,在创建代理类时跳过接口的查找和设置,最后创建CGLIB代理(我的结论和网上不一样,网上说的是会根据是否实现接口使用不同的代理方式,但我看到的并不是这样
  2. AutoProxyRegister的作用主要是创建事务自动代理创建类

ProxyTransactionManagementConfiguration做了什么

ProxyTransactionManagementConfiguration的作用主要是注册了切点pointCut、代理逻辑advice。

这里@Role忽略掉,不重要。

这里注入了3个bean如下3个bean,以完成代理对象拦截代理逻辑

image-20230521220410318

TransactionInterceptor:事务的advice,继承于TransactionAspectSupport,事务的核心类,事务的管理,提交,回顾等各种处理细节由它实现。

TransactionAttributeSource:提供事务注解@Transactional的属性获取,以及是否切点的判断()

BeanFactoryTransactionAttributeSourceAdvisor:继承AbstractPointcutAdvisor,事务的advisor:pointCut + advice,最后就是ProxyFactory中获取的advisor;

txManager:事务管理器,类:TransactionManager,由父类注入

这里说明一下TransactionAttributeSource为何没有实现Pointcut,但是切点。

其实这里BeanFactoryTransactionAttributeSourceAdvisor的切点逻辑是代理给了TransactionAttributeSource处理的。

image-20230521220534707

总结:

  1. 注册了代理需要的切点(什么类需要代理);
  2. 代理逻辑(开启事务、执行jdbc、回滚等详细的逻辑),包含事务管理器的注入

事务代理过程

他们都继承自AbstractAdvisorAutoProxyCreator,并且也都是BeanPostProcessor的子类,而且InfrastructureAdvisorAutoProxyCreator并没有重写什么方法,所以创建代理的过程和AOP章节是一样的:

初始化bean后置处理器调用:

image-20230521184413922

image-20230521184505579image-20230523224527494

image-20230521190008982

AutoProxyregistrar中进行了proxyTargetClass的设置,就是通过proxyFactory.copyFrom(this);代码复制的:这里的this就是InfrastructureAdvisorAutoProxyCreator,继承ProxyConfig,虽然它的类里没有定义属性proxyTargetClass,但是在AutoProxyregistrar中手动的为它的beanDefinition添加了这个属性。

所以,不会走下面的代码,直接就进行advisor的获取

if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

到这,就已经生成了每个事务代理对象。

如何完成的事务代理

好的,这里我们直接从TransactionInterceptor看,他是代理方法执行的入口,原因看上面,有解释。

位置:org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

// tas提供事务注解`@Transactional`的属性获取,以及是否切点的判断
TransactionAttributeSource tas = getTransactionAttributeSource();
// tas 绝对不会为null,在自动配置初始化就已经设置进去了
// 获取方法上的@Transactional属性信息
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 获取事务管理器,
// 因为自动配置(TransactionAutoConfiguration)注入的是DataSourceTransactionManagerAutoConfiguration,
// 所以这里的tm是DataSourceTransactionManager
		final TransactionManager tm = determineTransactionManager(txAttr);

// 这段是reactive的代码,不用理会
		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
			// ......
		}
// 这里是转换为父类,面向接口
		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// 生成事务方法标识
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
	if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			// 事务信息
        // 0.生成事务标识
        // 1. 先创建数据源对象DataSourceTransactionObject
        // 2. 从线程缓存中获取connectionHolder
        // 3. 两个分支:
        // 	  3.1 没有存在事务
        // 			3.1.1. 判断是否需要开启事务:REQUIRED/REQUIRES_NEW/NESTED
        //			3.1.2. 创建事务维护对象TransactionStatus
        // 			3.1.3. 从DataSource中获取一个connection,并设置到connectionHolder中
        // 			3.1.4. 设置事务属性:状态,事务级别,只读false
        //			3.1.5. 禁止自动提交:autoCommit=false
        //			3.1.6. 设置事务激活状态,超时时间
        //			3.1.7. 将connectionHolder以DataSource为key设置到线程缓存resource中
        //			3.1.8. 激活当前事务:设置事务状态、属性等到当前线程变量里
        // 4. 将事务线程里的事务信息设置到当前的事务信息里,用于回退,然后绑定当前的事务信息到线程缓存里
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				// 执行业务方法逻辑
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// 会先判断是否是我们指定的异常,如果是就会滚,如果不是,继续commit
                // 这里会恢复被挂起的事务信息
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
                // 清除事务信息
                // 回退到上一个事务信息,如果上一个事务信息不存在,那么就结束事务了
				cleanupTransactionInfo(txInfo);
			}
// vavr类存在才会走,不用理会
			if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				// Set rollback-only in case of Vavr failure matching our rollback rules...
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}
		// 提交事务
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

这段是一个完整的事务处理,进入createTransactionIfNecessary方法,看它如何获取的

image-20230525222754540

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

		// 如果事务属性的名称不存在,则将之前创建的事务标识设置进去
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}
// 事务维护对象:它保存了事务信息对象、事务的是否提交、是否回滚、和挂起的resource等信息
		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
                // 获取事务
                // 1. 先创建数据源对象DataSourceTransactionObject
                // 2. 从线程缓存中获取connectionHolder
                // 3. 两个分支:
                // 	  3.1 没有存在事务
                // 		3.1.1. 判断是否需要开启事务:REQUIRED/REQUIRES_NEW/NESTED
                //		3.1.2. 创建事务维护对象TransactionStatus
                // 		3.1.3. 从DataSource中获取一个connection,并设置到connectionHolder中
                // 		3.1.4. 设置事务属性:状态,事务级别,只读false
                //		3.1.5. 禁止自动提交:autoCommit=false
                //		3.1.6. 设置事务激活状态,超时时间
                //		3.1.7. 将connectionHolder以DataSource为key设置到线程缓存resource中
                //		3.1.8. 激活当前事务:设置事务状态、属性等到当前线程变量里
                //	3.2 存在事务
                //  	3.2.1. NEVER传播机制:不允许有事务,报错
                //		3.2.2. NOT_SUPPORTED传播机制:不支持事务,
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
    // 包装对象
//     4. 将事务线程里的事务信息设置到当前的事务信息里,用于回退,然后绑定当前的事务信息到线程缓存里
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

进入getTransaction

image-20230525222829440

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

		// 事务定义信息
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
	// 获取当前线程的事务对象
    // 1. 先创建数据源对象DataSourceTransactionObject
    // 2. 从线程缓存中获取connectionHolder
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();
// 判断是否有连接处理器和事务是否已开启
		if (isExistingTransaction(transaction)) {
			// 存在事务,那么安装事务传播机制执行
			return handleExistingTransaction(def, transaction, debugEnabled);
		}
//3.1 没有存在事务
		// Check definition settings for new transaction.
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}

		// MANDATORY传播机制:如果当前事务不存在,则抛出Exception
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
    // REQUIRED默认的传播机制
    // REQUIRES_NEW新事务传播机制
    // NESTED嵌套传播机制
    // 除开这3种,其他的都不需要开启事务
//    3.1.1. 判断是否需要开启事务:REQUIRED/REQUIRES_NEW/NESTED
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
            // 创建挂起的事务信息,第一次开启事务,这里suspendedResources=null,就是没有可以被挂起的
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
                // 开启新事务
                // 初始化当前线程里的事务信息
//	3.1.2. 创建事务维护对象TransactionStatus
// 	3.1.3. 从DataSource中获取一个connection,并设置到connectionHolder中
// 	3.1.4. 设置事务属性:状态,事务级别,只读false
//	3.1.5. 禁止自动提交:autoCommit=false
//	3.1.6. 设置事务激活状态,超时时间
//	3.1.7. 将connectionHolder以DataSource为key设置到线程缓存resource中
//  3.1.8. 激活当前事务:设置事务状态、属性等到当前线程变量里
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + def);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}

第一次开启事务怎么执行

进入doGetTransaction

image-20230525223006053

	protected Object doGetTransaction() {
        // 创建数据源事务对象
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        // 初始默认设置,默认是false
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
        // 通过dataSource从线程中获取对应的连接处理器,用于管理数据库连接行为
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
        // 将connectingHolder设置到数据源事务对象中,之后判断一个事务是否存在,就是通过这个对象,判断是否有connectionHolder
        // 因为不管执行多少次,都是会走这一步
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

TransactionSynchronizationManager是同步机制的中的事务管理对象,它内部有NamedThreadLocal线程级变量,key为dataSource,value为ConnectionHolder

进入startTransaction里的doBegin方法

image-20230525222654060

image-20230525222539430

protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
            // 当没有connection处理器,或者事务不同步时就创建一个连接connection处理器
            // 这里可以直接理解为,没有连接就获取一个connection,生成connection处理器
            // 在上一步中,transaction对象,是从线程缓存中获取的,
            // 如果线程缓存中存在connectionHolder,(txObject.hasConnectionHolder() = true)
            // 那就表示已经走过这个方法:isSynchronizedWithTransaction()=true
            // 如果txObject.hasConnectionHolder()=false,那isSynchronizedWithTransaction()也是false(默认值)			
            if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                // 从DataSource中获取新连接
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
                // 生成connectionHolder,并设置到当前的事务对象里
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

            // 更改状态 isSynchronizedWithTransaction() = true
			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
           // 获取最终的connection
			con = txObject.getConnectionHolder().getConnection();

            // 把事务信息设置到connection
            // 并且,如果connection获取到的事务基本和@Transaction注解的基本不一样,就返回connection的事务级别,注意,connection是可能是上一次的,也可能是新创建的
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            // 将获取到的上一次事务的事务级别设置到当前的事务对象里,这里可以理解成事务的传播
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
            // 默认false
			txObject.setReadOnly(definition.isReadOnly());

			// 这里就是禁止自动提交,一切交由事务管理器去做
			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);
			// 事务的超时时间,默认无限制
			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			// Bind the connection holder to the thread.
			if (txObject.isNewConnectionHolder()) {
                // 如果是新的connectionHolder那就设置到线程缓存中
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}

		catch (Throwable ex) {
			if (txObject.isNewConnectionHolder()) {
				DataSourceUtils.releaseConnection(con, obtainDataSource());
				txObject.setConnectionHolder(null, false);
			}
			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
		}
	}

	private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        // 3.1.2. 创建事务维护对象TransactionStatus
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
        // 开启事务
        // 	3.1.3. 从DataSource中获取一个connection,并设置到connectionHolder中
        // 	3.1.4. 设置事务属性:状态,上一次的事务级别,只读false
        //	3.1.5. 禁止自动提交:autoCommit=false
        //	3.1.6. 设置事务激活状态,超时时间
        //	3.1.7. 将connectionHolder以DataSource为key设置到线程缓存resource中
		doBegin(transaction, definition);
        // 3.1.8. 激活当前事务:设置事务状态、属性等到当前线程变量里
		prepareSynchronization(status, definition);
		return status;
	}

最后一步:prepareTransactionInfo

image-20230526222031538

	protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, String joinpointIdentification,
			@Nullable TransactionStatus status) {
// 创建事务信息
		TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
		if (txAttr != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			// The transaction manager will flag an error if an incompatible tx already exists.
			txInfo.newTransactionStatus(status);
		}
		else {
			// The TransactionInfo.hasTransaction() method will return false. We created it only
			// to preserve the integrity of the ThreadLocal stack maintained in this class.
			if (logger.isTraceEnabled()) {
				logger.trace("No need to create transaction for [" + joinpointIdentification +
						"]: This method is not transactional.");
			}
		}
// 这里是将当前线程里缓存的事务信息绑定到当前的事务信息里(oldTransactionInfo)
        // 怎么说呢,这里其实就是将上一次的事务信息从线程缓存里拿到,然后设置到当前事务里,在需要回退到上一个状态时用
		txInfo.bindToThread();
		return txInfo;
	}

那么这里接着往下,应该是执行业务逻辑,以及回滚和提交。

我们再回到方法:

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

image-20230526221126991

看回滚的方法:

我们经常写@Transaction时,会添加rollbackFor属性,就是在这里使用的

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
						"] after exception: " + ex);
			}
            // 判断是否符合我们指定的异常
			if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
				try {
// 回滚	
 txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
				}
				catch (TransactionSystemException ex2) {
					logger.error("Application exception overridden by rollback exception", ex);
					ex2.initApplicationException(ex);
					throw ex2;
				}
				catch (RuntimeException | Error ex2) {
					logger.error("Application exception overridden by rollback exception", ex);
					throw ex2;
				}
			}
			else {
				// We don't roll back on this exception.
				// Will still roll back if TransactionStatus.isRollbackOnly() is true.
				try {
                    // 那不是我们指定的异常,则继续提交
					txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
				}
				catch (TransactionSystemException ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					ex2.initApplicationException(ex);
					throw ex2;
				}
				catch (RuntimeException | Error ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					throw ex2;
				}
			}
		}
	}

然后是清除事务信息cleanupTransactionInfo,底层是下面这段:

	private void restoreThreadLocalStatus() {
			// Use stack to restore old transaction TransactionInfo.
			// Will be null if none was set.
			transactionInfoHolder.set(this.oldTransactionInfo);
		}

这里也就对应了txInfo.bindToThread();这个方法,这里是回退到上一个事务信息,如果有的话

然后这一段:

能走到这里的是CallbackPreferringPlatformTransactionManager类,看其子类是JTA的,所以这里就没跟了,但应也是一样的逻辑。

image-20230526223532209

已存在事务怎么执行

如果一开始有事务的话,

org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

image-20230526225531187

private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {

    // NEVER传播机制,是不允许有事务的
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}
 // NOT_SUPPORTED传播机制,出现这个时,当前注解下的都没有事务,也没不要开启,所以没有doBegin
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction");
			}
            // 获取被挂起的事务信息,能走这段代码就说明,已存在事务,所以这里获取的是上一次开启的事务
			Object suspendedResources = suspend(transaction);
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
            // 生成一个新的没有事务信息TransactionStatus回去,同时也把上一次挂起的事务信息设置进去了
            // 挂起的事务信息在这次事务提交后或是异常时,是要进行操作的
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}
// REQUIRES_NEW新事物传播机制
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction, creating new transaction with name [" +
						definition.getName() + "]");
			}
            // 同样,挂起事务
             // 获取被挂起的事务信息,能走这段代码就说明,已存在事务,所以这里获取的是上一次开启的事务
			SuspendedResourcesHolder suspendedResources = suspend(transaction);
			try {
                // 开启事务,和上面解释过的方法的是同一个方法,同时也把上一次挂起的事务信息设置进去了
				return startTransaction(definition, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
		}
// NESTED传播机制:建立保存点,异常后回退到上一个保存点
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			if (!isNestedTransactionAllowed()) {
				throw new NestedTransactionNotSupportedException(
						"Transaction manager does not allow nested transactions by default - " +
						"specify 'nestedTransactionAllowed' property with value 'true'");
			}
			if (debugEnabled) {
				logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
			}
            // 默认true
			if (useSavepointForNestedTransaction()) {
				// 这里生成一个新的事务维护对象,newTransaction=false,这里用的还是之前的事务
				DefaultTransactionStatus status =
						prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
                // 这里是:getConnection().setSavepoint(SAVEPOINT_NAME_PREFIX + this.savepointCounter)
				status.createAndHoldSavepoint();
				return status;
			}
			else {
				// Nested transaction through nested begin and commit/rollback calls.
				// Usually only for JTA: Spring synchronization might get activated here
				// in case of a pre-existing JTA transaction.
				return startTransaction(definition, transaction, debugEnabled, null);
			}
		}

		// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
		if (debugEnabled) {
			logger.debug("Participating in existing transaction");
		}
    // 是否验证事务
		if (isValidateExistingTransaction()) {
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
				Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
                // 如果当前的事务级别不存在,或者与指定的级别不同,报错
				if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
					Constants isoConstants = DefaultTransactionDefinition.constants;
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] specifies isolation level which is incompatible with existing transaction: " +
							(currentIsolationLevel != null ?
									isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
									"(unknown)"));
				}
			}
            // 如果只读,报错
			if (!definition.isReadOnly()) {
				if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] is not marked as read-only but existing transaction is");
				}
			}
		}
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    // 生成信息的事务维护对象
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

事务挂起恢复

已经存在事务时,再开启事务,且传播机制是:NOT_SUPPORTED,REQUIRES_NEW时,会将之前的connectionHolder拿到,然后设置到SuspendedResourcesHolder挂起对象中,再将当前线程里的事务信息都清空,包括connectionHolder,那么后面就会去拿新的connection;而这个挂起对象,会设置到TransactionStatus事务维护对象中,在当前的事务执行完,或者异常时,就会恢复这个挂起对象。

	protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
        // 激活状态,这个只要执行了startTransaction方法都是true,即事务的已开启
        // 会执行的有:REQUIRES_NEW/NESTED传播机制
		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
			try {
				Object suspendedResources = null;
				if (transaction != null) {
                    // 清除掉:transaction里的connectionHolder,线程缓存里的connectionHolder
                    // 并返回清除的对象,也就是旧的connectionHolder
					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);
                // 再生成挂起的事务对象,并返回,之后再commit后或者rollback后使用
				return new SuspendedResourcesHolder(
						suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
			}
			catch (RuntimeException | Error ex) {
				// doSuspend failed - original transaction is still active...
				doResumeSynchronization(suspendedSynchronizations);
				throw ex;
			}
		}
        // 然后这里,我不知道它会在什么情况下会走到这里
		else if (transaction != null) {
			// Transaction active but no synchronization active.
			Object suspendedResources = doSuspend(transaction);
			return new SuspendedResourcesHolder(suspendedResources);
		}
		else {
            // 这里就是第一次开启事务时会返回,也就表示没有可被挂起的对象
			return null;
		}
	}

rollback

  1. 执行cleanupTransactionInfo将事务对象TransactionInfo恢复到上一次事务

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

image-20230527143426542

出现异常会先执行cleanupTransactionInfo,它底层是:

		private void restoreThreadLocalStatus() {
            // 如果时第一次开启的事务,oldTransactionInfo为null,否则,oldTransactionInfo是上一次的事务
			transactionInfoHolder.set(this.oldTransactionInfo);
		}

oldTransactionInfo对象在开启新事物时(REQUIRED/REQUIRES_NEW/NESTED)绑定到线程,也就是bindToThread(),这时oldTransactionInfo取的transactionInfoHolder,如果这时开启的事务之前已经开过了,那么这里,的transactionInfoHolder就是上一次的事务对象,就会形成一个类似链表的存在,每个节点都有两个属性:oldTransactionInfo上一个事务,transactionInfoHolder当前事务,那么也很容易形成链式反应。

	private void bindToThread() {
			this.oldTransactionInfo = transactionInfoHolder.get();
			transactionInfoHolder.set(this);
		}
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {

		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
						"] after exception: " + ex);
			}
                // 这里默认RuntimeException 和 Error 会被回退
            // 判断是否是我们指定的异常,即是否需要回滚
			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 {
				// 不需要回滚,则继续提交
				try {
					txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
				}
				catch (TransactionSystemException ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					ex2.initApplicationException(ex);
					throw ex2;
				}
				catch (RuntimeException | Error ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					throw ex2;
				}
			}
		}
	}

再往里走

image-20230527152614059

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
		try {
			boolean unexpectedRollback = unexpected;

			try {
                // 前置方法,可用于扩展
				triggerBeforeCompletion(status);
// 如果要保存点,也就是NESTED传播机制
				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");
					}
                    // 回滚:connection.rolaback
					doRollback(status);
				}
                // 不是上面两种情况的走这里
				else {
					// 这里判断参与事务的某个方法异常,是否需要全局回滚
                    // 设想一下,什么情况会进来?
                    // NESTED REQUIRES_NEW这两种都机制都在上面处理了,那么下面处理的就是REQUIRED
					if (status.hasTransaction()) {
						if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
							}
                            // 标记属性rollbackOnly=true
							doSetRollbackOnly(status);
						}
						else {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
							}
						}
					}
					else {
						logger.debug("Should roll back transaction but cannot - no transaction available");
					}
					// Unexpected rollback only matters here if we're asked to fail early
					if (!isFailEarlyOnGlobalRollbackOnly()) {
                        // 立即终止事务执行
						unexpectedRollback = false;
					}
				}
			}
			catch (RuntimeException | Error ex) {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				throw ex;
			}
// 后置方法
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

			// Raise UnexpectedRollbackException if we had a global rollback-only marker
			if (unexpectedRollback) {
				throw new UnexpectedRollbackException(
						"Transaction rolled back because it has been marked as rollback-only");
			}
		}
		finally {
            // 这个是重要方法:回退到挂载点
			cleanupAfterCompletion(status);
		}
	}

	private void cleanupAfterCompletion(DefaultTransactionStatus status) {
		status.setCompleted();
		if (status.isNewSynchronization()) {
			TransactionSynchronizationManager.clear();
		}
		if (status.isNewTransaction()) {
			doCleanupAfterCompletion(status.getTransaction());
		}
		if (status.getSuspendedResources() != null) {
			if (status.isDebug()) {
				logger.debug("Resuming suspended transaction after completion of inner transaction");
			}
			Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
            // 这里就是恢复挂载点的逻辑
            // 会生成挂载点的只有:NOT_SUPPORTED,REQUIRES_NEW
          
			resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
		}
	}
	

在恢复挂载点后,线程还是同一个,事务信息已经变成旧的信息,而我们的事务执行依靠代理,所以,外层代理时就是上一次的事务信息。

同样的commit里也有一样的方法cleanupAfterCompletion

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Nodejs】使用Nodejs搭建HTTP服务,并实现公网远程访问

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 转载自内网穿透工具的文章&#xff1a;使用Nodejs搭建HTTP服务&#xff0c;并实现公网远程访问「内网穿透」 前言 Node.js…

数据结构与算法·第2章【线性表】

线性结构具有以下基本特征&#xff1a; 有唯一的一个被称为首元素&#xff08;或头元素&#xff09;的元素&#xff0c;没有直接前驱&#xff1b;有唯一的一个被称为尾元素&#xff08;或尾节点&#xff09;的元素&#xff0c;没有直接后继。 数据元素之间存在一对一的线性关…

磐维数据库panweidb单节点服务器在centos7.9安装(研发环境)

一、系统环境优化 1.1 关闭SELINUX # 修改配置文件 cat /etc/selinux/config | grep -i SELINUX SELINUXdisabled# 关闭SELINUX setenforce 0 1.2 内核参数优化 vi /etc/sysctl.conf 添加# panweidb net.ipv4.tcp_max_tw_buckets 10000 net.ipv4.tcp_tw_reuse 1 net.ipv4.t…

ssm+springboot+java高校图书馆图书借阅座位预约管理系统系统

陕理工图书馆管理系统包括多个功能模块&#xff1a;图书类别管理模块、图书管理模块、读者管理模块、借阅管理模块、预约管理、推荐管理。管理员登入后&#xff0c;维护图书借阅的信息。本文介绍了使用Java技术开发陕理工图书馆管理系统的设计与实现过程&#xff0c;首先对实现…

【源码分析】【netty】FastThreadLocal 为什么快?

写在前面 接下来几篇文章&#xff0c;我们来聊一聊 netty 相关的。这里作者想先从 FastThreadLocal 开始说&#xff0c;而不是可能大家更熟悉的 reactor 啊&#xff0c;责任链设计啊&#xff0c;ByteBuf 啊&#xff0c;池化啊等等。不过虽然说 FastThreadLocal 熟知程度不如其…

2023年湖北建筑架子工报名流程?报名需要什么资料?考试一次过?

2023年湖北建筑架子工报名流程&#xff1f;报名需要什么资料&#xff1f;考试一次过&#xff1f; 建筑架子工证是建筑行业必备的证书之一&#xff0c;它是证明持有人可以在建筑工地上从事搭建脚手架、模板等施工工作的重要证明。启程别告诉你架子工的报名流程和资料。 百度搜一…

示范性微电子院校“抢人”,芯片赛道黄不了!

经常看到有同学问&#xff0c;“国内高校微电子专业最好的是哪所高校?”“想搞数字ic设计去哪所大学好呢&#xff1f;” 其实国内28所示范性微电子学院都是非常不错的选择。 2015年&#xff0c;九所示范性微电子院校名单公布&#xff0c;包括了清华大学、北京大学、复旦大学…

【7 Vue3 – Composition API】

1 认识Composition API Options API的弊端 setup函数 2 setup函数的参数 3 setup简单使用 1 注意不再有响应式数据 要做到响应式数据需要在数据定义时使用ref包装数据,并且在使用时,使用value解包 2 注意template要使用的数据或者函数,必须要return 返回才能被使用 <templa…

软考A计划-软件设计师笔记

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

MT4期货软件怎么使用?有哪些MT4期货软件使用知识?

现在MT4软件在投资市场上应用广泛&#xff0c;当然也包括期货交易市场&#xff0c;但有不少投资者不知道为什么一定要选择MT4期货软件&#xff0c;其实选择MT4期货软件的理由有很多&#xff0c;MT4作为一款交易软件&#xff0c;不仅能够为投资者提供准确的市场信息&#xff0c;…

02SpringCloud Nacos注册中心和配置中心与Sentinel服务熔断和流控

Nacos注册中心和配置中心 Nacos 是 Alibaba 开发的用于微服务管理的平台&#xff0c;核心功能&#xff1a;服务注册与发现和集中配置管理。 Nacos 作为服务注册发现组件&#xff0c;可以替换Spring Cloud 应用中传统的服务注册于发现组件&#xff0c;如&#xff1a;Eureka、C…

Ai作图可控性演进——从SD到MJ

背景 Ai作图从Diffusion模型开始&#xff0c;作图进入稳步发展快车道。然后用过diffusion系列作图的同学对产图稳定性&#xff0c;以及可控性都会颇有微词。diffusion系列作图方法在宏观层面上确实能够比较好的做出看上去还不错的图。然后当你细抠细节时候&#xff0c;发现这东…

如何在Windows 11更新后解决C盘已满的问题?

Windows 11比Windows 10需要占用C盘更多的空间&#xff0c;在升级到Windows 11后&#xff0c;如果升级后出现问题&#xff0c;安装程序可以帮你退回到Windows 10。无论怎样&#xff0c;在升级到Windows 11后&#xff0c;系统会自动制作以前的数据的副本&#xff0c;这会占用大量…

win7下java环境搭建以及jdk环境变量配置

很多人在搭建页游、手游时候经常遇到JAVA闪退&#xff0c;基本都是环境变量或者路径错误导致的。本章节主要讲解在win7系统环境下&#xff0c;java环境变量配置方法&#xff0c;java环境配置正确&#xff0c;才可以对apk程序进行反编译运行页游手游。其他操作系统环境变量大同小…

Mesh形变算法

前言&#xff1a; 作者正好因为动画、模拟仿真等等的重大需求需要预先研发离散形的模型Mesh的形变算法&#xff0c;并且要验证、研究适用的范围、特别是性能等等&#xff0c;摸着石头过河别喷&#xff0c;毕竟我主要是渲染、动画、引擎的对于计算几何、三维重建不是很熟悉&…

一体化医学影像平台PACS源码,影像存档与传输系统源码

PACS影像存档与传输系统源码 PACS即影像存档与传输系统&#xff0c;是医学影像、数字化图像技术、计算机技术和网络通讯技术相结合的产物&#xff0c;是处理各种医学影像信息的采集、存储、报告、输出、管理、查询的计算机应用程序。 是基于DICOM标准的医学影像管理系统&…

大龄、零基础,想转行做网络安全。怎样比较可行?这届粉丝可真难带

昨晚上真的给我气孕了。 对于一直以来对网络安全兴趣很大&#xff0c;想以此作为以后的职业方向的人群。 不用担心&#xff0c;你可以选择兼顾工作和学习&#xff0c;以步步为营的方式尝试转行到网络安全领域。 那么&#xff0c;网络安全到底要学些什么呢&#xff1f; &…

Kyligence 客户案例招商银行批发业务分析平台获评金融数字化最佳实践案例

近日&#xff0c;“2023 爱分析金融数字化最佳实践案例”评选结果正式揭晓。Kyligence 携手招商银行申报的“招商银行‘火眼’批发业务分析平台”项目经过领先性、案例创新性、应用成熟度、价值创造等维度综合评选&#xff0c;最终获评“金融数字化最佳实践案例”。 招商银行“…

c++输入输出文件操作stream

系列文章目录 C IO库 文章目录 系列文章目录前言一、文件IO概述coutcin其他istream类方法 文件输入和输出内核格式化总结 前言 一、文件IO 概述 c程序把输入和输出看作字节流。输入时&#xff0c;程序从输入流中抽取字节&#xff1a;输出时&#xff0c;程序将字节流插入到输…

进攻中型SUV,蔚来/小鹏的智能化「满配」能否撬动需求

251.29万辆&#xff0c;这是2022年中国市场&#xff08;不含进出口&#xff09;乘用车中型SUV交出的答卷&#xff0c;交付量仅次于紧凑型SUV&#xff0c;排名细分市场第二。在这份成绩单中&#xff0c;有几个数字特别醒目。 1、31.64万辆&#xff0c;这是排名这个细分市场交付量…