Spring Source Code (8) El principio de las transacciones

prefacio

Comprensión no superficial y profunda de la cooperación entre AOP y la lógica comercial para completar el negocio, el contenido del artículo es un poco largo, desmantelarlo puede afectar la coherencia lógica antes y después,

operación básica

Los pasos de la transacción de ejecución de la base de datos son los siguientes:

  1. Abrir transacción comenzar sql commit autocommit = on
  2. sql
  3. comprometerse
  4. Retroceder

Una transacción en mysql begincomienza y commitfinaliza, y los errores en la transacción se revertirán, y generalmente está habilitado autocommit=on, por lo que cada sql se comprometerá;

verificar

  1. Un método llama a dos inserciones, y las dos inserciones deben ser objetos de conexión separados, o el mismo objeto, pero autocommit=true en conexión
    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;
    }

Este método llama a insert dos veces, genera dos objetos de instancia de conexión connectiony auto commit=true como se muestra a continuación:

Localización del método: org.mybatis.spring.SqlSessionTemplate#insert(java.lang.String, java.lang.Object)

imagen-20230424223106266

  1. En la transacción Spring, debe ser el mismo objeto de conexión para garantizar que algunas operaciones de la base de datos se completen en la misma transacción.

Luego, anota:@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;
    }

Mirando de nuevo el objeto de conexión, encontrará que los objetos de conexión de las dos inserciones son los mismos y autocommit=false

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

imagen-20230424223206354

Así que aquí, el esquema básico de la transacción de Spring ha sido claro, y la gestión de la conexión por parte de Spring se utiliza para lograr el control de la transacción.

Mecanismo de propagación de la transacción Spring.

La gestión de los asuntos de Spring se realiza de hecho a través de la gestión de la conexión, pero este es solo nuestro entendimiento parcial. Los asuntos de Spring pueden hacer más de lo que imaginamos; la siguiente es la descripción oficial de las características de Spring: acceso a datos (spring.io )

En Spring, define 7 tipos como enumeraciones:

  • REQUERIDO (predeterminado): Asegúrese de que la conexión utilizada por el método con anotación de transacción y el método llamado dentro del método sea el mismo y en la misma transacción.

  • REQUIRES_NEW: cuando existe este tipo, Spring volverá a crear una conexión e iniciará una nueva transacción.

  • NESTED: mecanismo de propagación anidado. Si hay una transacción externa, se anidará una transacción, pero la transacción también está dentro del alcance de la transacción externa.

  • SOPORTES: Si no hay transacción en la capa externa, no se agregará ninguna transacción, pero la transacción interna tendrá efecto

  • OBLIGATORIO: use la transacción actual, si la transacción actual no existe, lance una excepción

  • NOT_SUPPORTED: Durante la cadena de llamadas al método, cuando ocurra NOT_SUPPORTED, la interrupción de la transacción no tendrá efecto, y en la siguiente cadena de llamadas, cuando aparezca REQUIRED, volverá a tener efecto.

  • NUNCA: modo no transaccional, si hay una transacción abierta dentro del método, se lanzará una excepción.

Su uso es tan simple como @Transactionalel tipo estándar en la anotación.

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

Descripción del mecanismo especial

El efecto del uso se explica aquí, y es fácil de entender cuando se mira el código fuente más adelante.

NO SOPORTADO

Durante la cadena de llamadas al método, cuando ocurra NOT_SUPPORTED, la interrupción de la transacción no tendrá efecto, y en la siguiente cadena de llamadas, cuando ocurra REQUIRED, volverá a tener efecto.

    /**
     * 外层 事务  生效
     */
    @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;
    }

El resultado son los dos siguientes:

imagen-20230508221612063

imagen-20230517220808838

ANIDADO

Mecanismo de propagación anidado, si hay una transacción externa, se anidará una transacción, pero la transacción también está dentro del alcance de la transacción externa.

  1. NESTEDLas transacciones se pueden revertir de forma independiente
  2. NESTEDLa capa externa consume la excepción del método de transacción, y las transacciones de la capa externa NESTEDson independientes entre sí, como los archivos del juego.
  3. Si la capa externa es anormal, la NESTEDtransacción interna también se revertirá
    /**
      外层 事务
     */
    @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;
    }

SOPORTES

SUPPORTSi no hay ninguna transacción en la capa externa, no se agregará ninguna transacción, pero la transacción interna tendrá efecto, de la siguiente manera:

// 外层 没事务
    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;
    }

código fuente

Clase de configuración automática de transacciones de carga

Muchos componentes en spring se cargan a través de clases de configuración automática, si es propio de spring, entonces spring-boot-autoconfigureen el siguiente spring.factories, podemos encontrar la siguiente clase de configuración en él:

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

¿Desea agregar anotaciones: @EnableTransactionManagement

De hecho, no necesitas usarlo. Los que están en @SpringBootApplicationél @EnableAutoConfigurationserán obtenidos spring.factories. Hay clases en TransactionAutoConfigurationél. Echemos un vistazo a una parte:

    @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() {
    
    
            }
        }
    }

Como se indicó anteriormente, inyectará una EnableTransactionManagementConfigurationclase de configuración y luego buscará anotaciones @EnableTransactionManagement, por lo que no necesita agregar anotaciones.

Descripción de la clase de configuración

TransactionAutoConfigurationLas siguientes anotaciones se agregan al encabezado de la clase de configuración:

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

@Configuration: Reconocido por spring como un logotipo de clase de configuración, pensemos aquí, ¿qué anotaciones hay para el logotipo reconocido por spring como una clase de configuración?

@ConditionalOnClass({PlatformTransactionManager.class}): Esto es PlatformTransactionManagerpara cargar la clase de configuración solo cuando hay una clase

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

Esta clase de configuración se carga después de que Spring cargue estas clases de configuración. Luego, si introduce spring-data-jdbc, esta clase de configuración existirá. Al mismo tiempo, se puede ver que admite: jta, jpa, jdbc, neo4j DataSourceTransactionManagerAutoConfiguration.

@EnableConfigurationProperties({TransactionProperties.class}): Parámetros de configuración de transacciones, puede definir spring.transaction.defaultTimeout/rollbackOnCommitFailureatributos

Entonces el punto es EnableTransactionManagement;

imagen-20230521165256022

imagen-20230521174128186

¿Qué hace EnableTransactionManagement?

Esta anotación tiene dos propiedades importantes:

proxyTargetClass : valor predeterminado: falso; verdadero: indica que se puede usar el proxy CGLIB, si hay una interfaz, todavía se usa el proxy dinámico jdk, falso: se usa el proxy dinámico JDK

modo : valor predeterminado: PROXY; PROXYCuando el valor es , significa usar proxy dinámico JDK, ASPECTJlo que significa usar Spring @Aspectpara el proxy de aspecto, debe tenerse en cuenta que PROXYlas llamadas locales a la misma clase no pueden ser interceptadas. Si desea lograr una intercepción avanzada , debes usarASPECTJ

Qué hace AutoProxyRegistrar

AutoProxyRegistrarLa función es registrar beanName como beanDefinition internalAutoProxyCreatorcomo la clase InfrastructureAdvisorAutoProxyCreator, que hereda de él AbstractAdvisorAutoProxyCreator.

AbstractAdvisorAutoProxyCreator: Esta clase se menciona en el capítulo AOP, es una clase de creación automática de proxy AOP, que realiza principalmente las siguientes operaciones:

  1. Primero, después de inicializar el bean, postProcessAfterInitializationse llamará a su método para el procesamiento de la clase proxy.
  2. Determinar si el bean necesita ser proxy
  3. Cree un objeto proxy (el proxy creado aquí se evaluará según el objeto)

Proxy AOP y proxy de transacción, ambos implementan el mismo AbstractAdvisorAutoProxyCreatory luego implementan implementaciones personalizadas para adaptarse a las funciones de diferentes escenarios.

imagen-20230521182932882

A continuación, mire AutoProxyRegistrarla implementación, porque está implementada ImportBeanDefinitionRegistrar, por lo que hace la operación lógica de registrar beans aquí.

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();
// 			......
		}
	}

Echa un vistazo aquí:

imagen-20230521184842385

imagen-20230521185004962

Establece una propiedad aquí proxyTargetClass, InfrastructureAdvisorAutoProxyCreatorque esinternalAutoProxyCreator beanName, si lo olvida, puede leer los comentarios del código anterior nuevamente;InfrastructureAdvisorAutoProxyCreator

Aquí .add("proxyTargetClass", Boolean.TRUE);, en esta clase, no hay ningún proxyTargetClassatributo, por lo que aquí se usa add, que está relacionado con la siguiente lógica, así que lo menciono aquí, de hecho, no tiene un significado real.

¿La clase de proxy creada es un proxy dinámico jdk o cglib?

Resultado: solo será un proxy CGLIB, no un proxy JDK. Vea a continuación el motivo.

EnableTransactionManagementSe establece en la anotación proxyTargetClass = true, lo que significa que se puede usar CGLIB, vea el código para crear una clase de proxy a continuación

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

Este método tiene tres juicios (el segundo se ignora):

  1. La primera if: determinar si se necesita optimización, si se debe usar el proxy cglib y si se debe especificar una interfaz: primero, al registrar y crear una clase, especifique el uso del proxy cblib ( ), y cuando esta condición surta efecto, no hay config.isProxyTargetClass()=trueinterfaz se realiza la búsqueda, y no se ha configurado Objeto de interfaz, es decir hasNoUserSuppliedProxyInterfaces(config)=false, pero aquí está o, por lo que entra el primer juicio
  2. El tercero if: juzgue targetClasssi es un tipo de interfaz, tenga en cuenta que el código aquí se ejecuta después de que se inicializa el bean, por lo que esta targetClass no es un tipo de interfaz, entonces, targetClass.isInterface()=falsey vamos a representar la transacción, correcto, entonces Proxy.isProxyClass(targetClass)=false, entonces el tercero si no es entrar directamentereturn new ObjenesisCglibAopProxy(config);

Ilustración:

imagen-20230523222510837

En el capítulo anterior de AOP, se mencionó que en el proxy automático de Spring, si el objeto proxy tiene una interfaz, entonces se usará el proxy JDK y se usará cglib si no hay nadie;

Y aquí, debido a proxyTargetClass=truela influencia de los atributos, irá al tercero si el juicio, y el tercero si es todo falso, por lo que todos son proxies cglib.

Resumir:

  1. EnableTransactionManagementConfigurationSe configuran dos anotaciones en la clase de configuración y @EnableTransactionManagementlas propiedades son diferentes, pero siempre que una de las propiedades sea: proxyTargetClass = trueok, cuando sea verdadera, se registrará la clase de creación del proxy de transacción InfrastructureAdvisorAutoProxyCreatory se proxyTargetClass = trueestablecerán las configuraciones en ella. al crear la clase de proxy Después de buscar y configurar la interfaz, finalmente cree un proxy CGLIB ( mi conclusión es diferente a la de Internet. Se dice en Internet que se usarán diferentes métodos de proxy dependiendo de si se implementa la interfaz, pero lo que veo no es el caso )
  2. AutoProxyRegisterLa función principal es crear una clase de creación automática de proxy de transacción.

Qué hace ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfigurationLa función principal es registrar el punto de corte y el consejo de lógica de proxy.

@RoleIgnóralo aquí , no es importante.

Aquí, se inyectan tres beans de la siguiente manera para completar la lógica de proxy de intercepción de objetos proxy

imagen-20230521220410318

TransactionInterceptor: el consejo de transacciones, heredado de TransactionAspectSupport, la clase principal de transacciones, la gestión de transacciones, el envío, la revisión y otros detalles de procesamiento son implementados por él.

TransactionAttributeSource: proporciona @Transactionalla adquisición de atributos de las anotaciones de transacciones y el juicio de si se deben cortar puntos ()

BeanFactoryTransactionAttributeSourceAdvisor: herencia AbstractPointcutAdvisor, asesor de transacciones: pointCut + consejo, y finalmente el asesor obtenido en ProxyFactory;

txManager: administrador de transacciones, clase:, TransactionManagerinyectado por la clase principal

Aquí hay una explicación de TransactionAttributeSourcepor qué no se implementa Pointcut, pero se corta el punto.

De hecho, BeanFactoryTransactionAttributeSourceAdvisorla lógica de corte de puntos aquí es TransactionAttributeSourcemanejada por el agente.

imagen-20230521220534707

Resumir:

  1. Registrado el punto de corte requerido por el proxy (qué clase necesita un proxy);
  2. Lógica de proxy (lógica detallada como abrir transacciones, ejecutar jdbc, revertir, etc.), incluida la inyección del administrador de transacciones

Proceso de proxy de transacción

Todos heredan de AbstractAdvisorAutoProxyCreator, y también son BeanPostProcessorsubclases de, y InfrastructureAdvisorAutoProxyCreatorno anulan ningún método, por lo que el proceso de creación de un proxy es el mismo que el del capítulo AOP:

Inicialice la llamada al posprocesador del bean:

imagen-20230521184413922

imagen-20230521184505579imagen-20230523224527494

imagen-20230521190008982

Las configuraciones AutoProxyregistrarrealizadas en se copian a través del código: aquí esto es , herencia , aunque no hay un atributo definido en su clase , pero este atributo se agrega manualmente a su beanDefinition en.proxyTargetClassproxyFactory.copyFrom(this);InfrastructureAdvisorAutoProxyCreatorProxyConfigproxyTargetClassAutoProxyregistrar

Por lo tanto, no se utilizará el siguiente código y el asesor se obtendrá directamente.

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

En este punto, se ha generado cada objeto proxy de transacción.

Cómo completar el proxy de transacción

Bien, aquí TransactionInterceptorvemos directamente que es el punto de entrada para la ejecución del método proxy, la razón se explica arriba.

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

Esta sección es un procesamiento de transacción completo, ingrese createTransactionIfNecessaryel método para ver cómo se obtiene

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

IngresargetTransaction

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

Cómo iniciar una transacción por primera vez

IngresardoGetTransaction

imagen-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 es un objeto de gestión de transacciones en el mecanismo de sincronización.Tiene NamedThreadLocalvariables a nivel de hilo dentro, con clave dataSourcey valor ConnectionHolder.

startTransactioncomo entrar doBegin_

imagen-20230525222654060

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

El último paso: prepareTransactionInfo

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

Luego, el siguiente paso aquí debería ser ejecutar la lógica comercial, así como revertir y confirmar.

Volvamos al método:

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

imagen-20230526221126991

Vea cómo retroceder:

Cuando escribimos a menudo @Transaction, agregamos rollbackForatributos, que se usan aquí

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

Luego borre la información de la transacción cleanupTransactionInfo, la capa inferior es el siguiente párrafo:

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

Aquí también corresponde a txInfo.bindToThread();este método, aquí está la reversión a la información de la transacción anterior, si la hay

Entonces este párrafo:

Es la clase que puede llegar aquí CallbackPreferringPlatformTransactionManager, y su subclase es JTA, por lo que no se sigue aquí, pero debería ser la misma lógica.

imagen-20230526223532209

Cómo ejecutar transacciones existentes

Si hay negocios al principio,

org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

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

recuperación de suspensión de transacción

Cuando ya existe una transacción, reinicie la transacción y el mecanismo de propagación es: NOT_SUPPORTED,REQUIRES_NEW, se obtendrá el connectionHolder anterior y luego se establecerá en SuspendedResourcesHolderel objeto pendiente, y luego toda la información de la transacción en el subproceso actual, incluido el connectionHolder, será borrado más tarde Obtenga uno nuevo connection, y este objeto suspendido se establecerá en TransactionStatusel objeto de mantenimiento de transacciones, y el objeto suspendido se restaurará cuando se ejecute la transacción actual o se produzca una excepción.

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

Retroceder

  1. Ejecutar revierte cleanupTransactionInfoel objeto de transacción TransactionInfoa la transacción anterior

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

imagen-20230527143426542

Cuando ocurre una excepción, se ejecutará primero cleanupTransactionInfo. Su capa inferior es:

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

oldTransactionInfoREQUIRED/REQUIRES_NEW/NESTEDEl objeto se vincula al hilo al abrir algo nuevo ( ), es decir bindToThread(), oldTransactionInfose toma en este transactionInfoHoldermomento. Si la transacción abierta en este momento se ha abierto antes, entonces aquí transactionInfoHolderse formará el objeto de transacción de la última vez. Una lista enlazada similar La existencia de cada nodo tiene dos atributos: oldTransactionInfola transacción anterior y transactionInfoHolderla transacción actual, por lo que es fácil formar una reacción en cadena.

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

ir más lejos en

imagen-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());
		}
	}
	

Después de restaurar el punto de montaje, el hilo sigue siendo el mismo, la información de la transacción se ha convertido en información antigua y la ejecución de nuestra transacción depende del agente, por lo que el agente externo es la información de la última transacción.

Hay el mismo método en el mismo compromiso cleanupAfterCompletion.

Supongo que te gusta

Origin blog.csdn.net/qq_28911061/article/details/130902555
Recomendado
Clasificación