Spring之声明式事务

本文深入探讨了Spring声明式事务的实现,从注解入口开始,解析了事务拦截器、事务创建、提交、回滚的过程。详细介绍了如何获取和开启事务,以及在已有事务时的不同处理,包括savepoint和rollbackOnly的机制。最后总结了事务创建的流程,并讨论了事务恢复的处理。
摘要由CSDN通过智能技术生成

入口

Spring中,我们可以通过@EnableTransactionManagement开启声明式事务;但在SpringBoot我们发现不打这个注解也开启了声明式事务,这是为什么呢?答案就在org.springframework.boot:spring-boot-autoconfigure这个包里的spring.factories(spring.factories放了很多需要容器管理的实例的类路径;三方jar包可以通过这种方式将自己的一些Bean交托给Spring容器管理), 这个文件告诉Spring容器,它有个org.springframework.boot.autoconfigure.transaction.TransactionAutoConfigurationJavaConfig要托付。

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

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(TransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		public static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		public static class CglibAutoProxyConfiguration {

		}

	}

}

spring.aop.proxy-target-class默认为true

注解@EnableTransactionManagement

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	boolean proxyTargetClass() default false;

	AdviceMode mode() default AdviceMode.PROXY;

	int order() default Ordered.LOWEST_PRECEDENCE;
}

又看到了熟悉的@Import注解,这个注解在@Enablexxxx系列的注解中经常看到。导入的是ImportSelector的实现类,会执行类里的String[] selectImports(AnnotationMetadata importingClassMetadata);方法

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

    // 这个方法在父类`AdviceModeImportSelector`的`selectImports(org.springframework.core.type.AnnotationMetadata)`中被调用
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

	private String determineTransactionAspectClass() {
		...
	}
}

// org.springframework.context.annotation.AdviceModeImportSelector#selectImports
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
	Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
	Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
    // 获取@EnableTransactionManagement的全部属性
	AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
	if (attributes == null) {
		throw new IllegalArgumentException(String.format(
				"@%s is not present on importing class '%s' as expected",
				annType.getSimpleName(), importingClassMetadata.getClassName()));
	}
    // 获取@EnableTransactionManagement里的`mode`属性值,这里是`PROXY`
	AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
	// 调用`TransactionManagementConfigurationSelector`的`selectImports(AdviceMode adviceMode)`
	// 这里返回的是new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}
	String[] imports = selectImports(adviceMode);
	if (imports == null) {
		throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
	}
	return imports;
}

最终添加的Bean方法如下:

public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    // 这是一个`PointcutAdvisor`,增强器
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

    // 这是一个`MethodInterceptor`,主要处理事务的逻辑
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}
// 父类`AbstractTransactionManagementConfiguration`
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}

}

进行到这里,通过@EnableTransactionManagement,我们添加了一个ImportBeanDefinitionRegistrar->AutoProxyRegistrar,以及4个@Bean方法。AutoProxyRegistrar里我们注入了org.springframework.aop.config.internalAutoProxyCreator这个bean,是InfrastructureAdvisorAutoProxyCreator类。在SpringBoot里,我们有自动加载AopAutoConfiguration,会用AnnotationAwareAspectJAutoProxyCreator替换InfrastructureAdvisorAutoProxyCreator。4个Bean分别为:

  • BeanFactoryTransactionAttributeSourceAdvisor: 这是最终的一个Advisor;
  • TransactionAttributeSource: 从配置、源级别的元数据属性或其他任何地方获取事务属性;这里用的是AnnotationTransactionAttributeSource,通过SpringTransactionAnnotationParser解析@Transactional注解,获取里面的transactionManager/propagation/isolation等属性;
  • TransactionInterceptor: 真正执行事务拦截的地方。这里的txManager一开始是null;
  • TransactionalEventListenerFactory: 事务的事件监听;目前还没用到,先略过…;

事务拦截

前面我们从声明式注解的入口开始,一步步分析,最终找到了它使用的拦截器TransactionInterceptor。现在开始,正式分析我们的增强器里的业务逻辑。

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// 真正执行,同时传入invocation::proceed,通知调用链进行下一个增强
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}
}

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

		// 在ProxyTransactionManagementConfiguration里TransactionInterceptor是传入的
		// 这里的类型为AnnotationTransactionAttributeSource
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 通过SpringTransactionAnnotationParser将@Transactional里的属性解析到TransactionAttribute对象里
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		// 根据注解里的value/transactionManager指定的beanname,获取TransactionManager
		// TransactionManager默认是由DataSourceTransactionManagerAutoConfiguration里导入的DataSourceTransactionManager
		final TransactionManager tm = determineTransactionManager(txAttr);
        // 这需要在我们引入了org.reactivestreams:reactive-streams这个包,并且事务管理器为ReactiveTransactionManager才会生效。这里先略过...
		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
			ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
				...
			});
			return txSupport.invokeWithinTransaction(
					method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
		}

		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		// 方法标识 className.methodName
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
        // DataSourceTransactionManager满足不是CallbackPreferringPlatformTransactionManager这个条件
		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			// 这里是重点,创建事务
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				// advisor调用链向后执行
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// 抛出异常后的处理
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
			    // 重置TransactionInfo ThreadLocal
			    // 事务里用到里好几个ThreadLocal
				cleanupTransactionInfo(txInfo);
			}
            // 如果结果是一个Vavr.Try,会尝试执行下,看会不会抛出rollback的异常
            // 如果会,就把事务设置为readonly
			if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}
            // 提交事务
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			Object result;
			// 如果trasactionManager是一个CallbackPreferringPlatformTransactionManager
			// 在这里进行处理
			// 这里先省略,把创建事务/事务回滚以及事务提交先捋顺了
			return result;
		}
	}
}

创建事务

createTransactionIfNecessary创建一个事务。

// tm是一个DataSourceTransactionManager类型
// txAttr是我们从@Transactional注解里拿到的属性,可能会有指定的tracationManager的beanName,事务隔离级别,事务传播,指定异常回滚等
// joinpointIdentification是在上面获取到的classname.methodname的字符串
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
		@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

	// 如果没有指定这个事务属性对象的名称
	// 就用DelegatingTransactionAttribute包装它,用joinpointIdentification作为它的名字
	if (txAttr != null && txAttr.getName() == null) {
		txAttr = new DelegatingTransactionAttribute(txAttr) {
			@Override
			public String getName() {
				return joinpointIdentification;
			}
		};
	}

	TransactionStatus status = null;
	// 这里先假设txAttr/tm都不为空
	if (txAttr != null) {
		if (tm != null) {
		    // 准备TransactionStatus
			status = tm.getTransaction(txAttr);
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
						"] because no transaction manager has been configured");
			}
		}
	}
	// 准备transaction info
	return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

我们先看tm.getTransaction方法,这里我们使用的是tmDataSourceTransactionManager

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

	// 如果没有事务属性就用默认的
	TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    
    // 真正获取一个事务对象
	Object transaction = doGetTransaction();
	boolean debugEnabled = logger.isDebugEnabled();
    // 判断这个事务对象是否有一个进行中的事务
    // 如果有,在DataSourceTransactionManager里是根据事务属性里的事务传播属性来进行下一步的
    // 有PROPAGATION_NEVER,PROPAGATION_NOT_SUPPORTED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED,PROPAGATION_REQUIRED,PROPAGATION_SUPPORTS,PROPAGATION_MANDATORY这7种
    // PROPAGATION_REQUIRED:如果当前存在事务就继续沿用,没有就创建一个新的
    // PROPAGATION_SUPPORTS:如果当前存在事务就继续沿用,没有就以非事务模式执行
    // PROPAGATION_MANDATORY:如果当前存在事务就继续沿用,没有存在的事务就抛出异常
    // PROPAGATION_NEVER:不支持已存在事务,会抛出异常
    // PROPAGATION_NOT_SUPPORTED:总是以非事务模式执行,如果之前有事务,则把前面那个事务挂起
    // PROPAGATION_REQUIRES_NEW:创建一个新的事务,把之前的事务挂起
    // PROPAGATION_NESTED:如果当前存在事务嵌套(savepoint)的方式执行,没有就创建一个新的
	if (isExistingTransaction(transaction)) {
		return handleExistingTransaction(def, transaction, debugEnabled);
	}

	// 校验事务是否超时
	if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
		throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
	}

	// 到这一步,说明当前不存在事务,
	// 如果propagation属性为PROPAGATION_MANDATORY就抛出异常
	if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
		throw new IllegalTransactionStateException(
				"No existing transaction found for transaction marked with propagation 'mandatory'");
	}
	else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
			def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
			def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			// PROPAGATION_REQUIRED/PROPAGATION_REQUIRES_NEW/PROPAGATION_NESTED
			// 这三种方式在当前不存在事务的情况下,都会新建一个
			// 另外3中在当前没有事务的情况下是不会开启事务的,这里就不管了
			// 挂起,具体作用见下文
		SuspendedResourcesHolder suspendedResources = suspend(null);

		try {
		    // 开启事务
			return startTransaction(def, transaction, debugEnabled, suspendedResources);
		}
		catch (RuntimeException | Error ex) {
		    // 恢复
			resume(null, suspendedResources);
			throw ex;
		}
	}
	else {
		// 不需要创建事务,但可能有潜在的事务拓展
		...
		boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
		return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
	}
}

在上文中,我们了解到Spring定义了7种事务的传播方式,来处理当前不存在事务与当前存在事务的场景;又涉及到获取事务,开启事务,事务挂起,savepoint这4个动作。接下来,我们先分开讲这4个动作,最后再合起来。

获取事务

// 上文提到我们用到的tm是DataSourceTransactionManager
// 所以这里用的是DataSourceTransactionManager#doGetTransaction
protected Object doGetTransaction() {
	DataSourceTransactionObject txObject = new DataSourceTransactionObject();
	// 默认nestedTransactionAllowed是false
	txObject.setSavepointAllowed(isNestedTransactionAllowed());
	// 从ThreadLocal里获取连接,首次获取其实是null
	ConnectionHolder conHolder =
			(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
	txObject.setConnectionHolder(conHolder, false);
	return txObject;
}

这里的事务实际上只是一个DataSourceTransactionObject对象,设置了savepointAllowed属性以及connectionHolderconnectionHolder第一次获取时还是为null的。

开启事务

开启事务有3种场景:1. 当前无事务,开启事务;2. 当前有事务,挂起当前事务,开启新事务;3. jta事务嵌套,开启新事务。

private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
    // transactionSynchronization默认是SYNCHRONIZATION_ALWAYS
    // 所以这里newSynchronization=true
	boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
	// suspendedResources是suspend(null)方法返回的
	// 在下面讲到挂起时,再返回来讲
	// 我们把事务,事务属性以及suspendedResources都保存到这个DefaultTransactionStatus里了
	// 并且newTransaction/newSynchronization都为true
	DefaultTransactionStatus status = newTransactionStatus(
			definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
	// 真正开启一个事务
	doBegin(transaction, definition);
	// 初始话事务扩展
	prepareSynchronization(status, definition);
	return status;
}
doBegin
protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

	try {
	    // 前面说过 第一次getTransaction时connectionHolder其实是null
	    // 所以满足这里的条件, 然后从连接池里获取一个连接
	    // 创建新的ConnectionHolder并设置到transaction里, 再将transaction的newConnectionHolder属性设置为true
		if (!txObject.hasConnectionHolder() ||
				txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			Connection newCon = obtainDataSource().getConnection();
			...
			txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
		}
        // 标记这个连接资源与事务同步
		txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
		con = txObject.getConnectionHolder().getConnection();

		Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
		txObject.setPreviousIsolationLevel(previousIsolationLevel);
		txObject.setReadOnly(definition.isReadOnly());

		// 如果这个数据库连接是自动提交的,将自动提交设置为false
		if (con.getAutoCommit()) {
			txObject.setMustRestoreAutoCommit(true);
			...
			con.setAutoCommit(false);
		}
        // 判断我们给的事务是不是只读的
        // 是的话,执行"SET TRANSACTION READ ONLY"这个语句
		prepareTransactionalConnection(con, definition);
		txObject.getConnectionHolder().setTransactionActive(true);

		int timeout = determineTimeout(definition);
		if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
			txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
		}

		// 如果是新建的ConnectionHolder
		// 以datasource为键,新建的ConnectionHolder为value,设置到ThreadLocal里去
		// 下次可以根据datasource获取当前Thread的ConnectionHolder对象
		if (txObject.isNewConnectionHolder()) {
			TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
		}
	}

	catch (Throwable ex) {
		...
	}
}

doBegin这个方法主要做了3件事:1. 获取数据库连接;2. 将连接的autoCommit属性设置为false,不自动提交了;3. 将连接与当前线程绑定。

prepareSynchronization
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
    // 这里status的newSynchronization为true
    // 其实就是将DefaultTransactionStatus的信息设置到TransactionSynchronizationManager的静态变量里
    // 然后初始化TransactionSynchronizationManager的synchronizations属性
	if (status.isNewSynchronization()) {
		TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
		TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
				definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
						definition.getIsolationLevel() : null);
		TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
		TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
		TransactionSynchronizationManager.initSynchronization();
	}
}

如果是新的事务扩展,就将当前事务的属性设置到TransactionSynchronizationManager里去。

挂起

在当前已有事务的情况下,在部分传播方式下,会将当前的事务挂起,然后创建一个新的事务。

protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
    // 根据prepareSynchronization方法里的逻辑,
    // 在已存在事务的条件下,synchronizationActive为true
	if (TransactionSynchronizationManager.isSynchronizationActive()) {
	    // 获取ThreadLocal里的synchronizations
	    // 依次执行它们的suspend后将synchronizations从ThreadLocal里移除
	    // 返回获取到的synchronizations
		List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
		try {
			Object suspendedResources = null;
			if (transaction != null) {
			    // 真正的挂起
				suspendedResources = doSuspend(transaction);
			}
			// 将当前TransactionSynchronizationManager里的信息/suspendedSynchronizations以及事务对象里挂起的资源保存到SuspendedResourcesHolder里
			String name = TransactionSynchronizationManager.getCurrentTransactionName();
			TransactionSynchronizationManager.setCurrentTransactionName(null);
			boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
			TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
			Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
			TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
			boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
			TransactionSynchronizationManager.setActualTransactionActive(false);
			return new SuspendedResourcesHolder(
					suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
		}
		catch (RuntimeException | Error ex) {
			// doSuspend failed - original transaction is still active...
			doResumeSynchronization(suspendedSynchronizations);
			throw ex;
		}
	}
	else if (transaction != null) {
		Object suspendedResources = doSuspend(transaction);
		return new SuspendedResourcesHolder(suspendedResources);
	}
	else {
		return null;
	}
}

现在反过来想下在getTransaction方法里,当当前没有事务,而传播方式需要创建一个事务对象时

SuspendedResourcesHolder suspendedResources = suspend(null);

这里做了啥。

// TransactionSynchronizationManager.isSynchronizationActive()
public static boolean isSynchronizationActive() {
	return (synchronizations.get() != null);
}

当我们第一次进来的时候ThreadLocal里的synchronizations为null, 且transaction也为null,所以suspendedResources也为null;既返回的DefaultTransactionStatus对象里的suspendedResources为null。

doSuspend
protected Object doSuspend(Object transaction) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	txObject.setConnectionHolder(null);
	return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}

doSuspend方法很简单,就是将当前事务对象里的连接信息清空,并将之前设置到ThreadLocal里的与当前datasource绑定的ConnectionHolder解除。返回移除的ConnectionHolder对象,这个对象会保存到SuspendedResourcesHolder里。

savepoint

当传播方式是PROPAGATION_NESTED有可能会创建一个savepoint

DefaultTransactionStatus status =
						prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();

createAndHoldSavepoint委托transactionConnectionHolder里真正的数据库连接创建savepoint,并将返回的Savepoint对象设置到statussavepoint属性里。

已存在事务时的处理

在上面getTransaction方法里,我们了解到,当当前存在一个事务时,会发生抛出异常、挂起、savepoint这三种情况,下面我们具体看下这方面的代码:

private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {
    // 传播方式为PROPAGATION_NEVER,则抛出异常
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
		throw new IllegalTransactionStateException(
				"Existing transaction found for transaction marked with propagation 'never'");
	}
    // 传播方式为PROPAGATION_NOT_SUPPORTED,则挂起当前事务,并在非事务模式下执行
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
		...
		Object suspendedResources = suspend(transaction);
		boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
		return prepareTransactionStatus(
				definition, null, false, newSynchronization, debugEnabled, suspendedResources);
	}
    // 传播方式为PROPAGATION_REQUIRES_NEW,则挂起当前事务,开始一个新的事务
    // startTransaction会获取一个新的数据库连接
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
		...
		SuspendedResourcesHolder suspendedResources = suspend(transaction);
		try {
			return startTransaction(definition, transaction, debugEnabled, suspendedResources);
		}
		catch (RuntimeException | Error beginEx) {
			resumeAfterBeginException(transaction, suspendedResources, beginEx);
			throw beginEx;
		}
	}
    // 如果传播方式为PROPAGATION_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'");
		}
		...
		// 如果支持savepoint就创建一个savepoint
		// jta事务不支持savepoint,其他默认都支持
		if (useSavepointForNestedTransaction()) {
			DefaultTransactionStatus status =
					prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
			status.createAndHoldSavepoint();
			return status;
		}
		else {
			// jta事务,这里不扩展分析了
			return startTransaction(definition, transaction, debugEnabled, null);
		}
	}

	// 传播方式为PROPAGATION_SUPPORTS、PROPAGATION_REQUIRED、PROPAGATION_MANDATORY
	// 是否需要验证当前事务的有效性,默认是false,不验证
	if (isValidateExistingTransaction()) {
	    // 校验声明的事务属性的事务隔离级别与默认/当前TransactionSynchronizationManager里的事务隔离级别是否一致
		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)"));
			}
		}
		// 校验声明的事务属性里的readonly属性与TransactionSynchronizationManager里的只读属性是否一致
		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);
	// 创建一个新的TransactionStatus,并初始化事务扩展(synchronizations)
	return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

至此我们知道了在已存在一个事务对象的情况下,会根据事务的传播方式进行不同的处理。

获取到TransactionStatus后处理

我们通过上述步骤获取到TransactionStatus后,还要通过prepareTransactionInfo方法进一步封装。

protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
		@Nullable TransactionAttribute txAttr, String joinpointIdentification,
		@Nullable TransactionStatus status) {
    // 根据当前方法信息,事务属性,事务管理器创建TransactionInfo
	TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
	if (txAttr != null) {
		// 将TransactionStatus保存到TransactionInfo
		txInfo.newTransactionStatus(status);
	}
	else {
		...
	}
    // 将TransactionInfo绑定到ThreadLocal
    // 变量名为transactionInfoHolder
	txInfo.bindToThread();
	return txInfo;
}

我们发现非事务模式下,也会创建一个TransactionStatus,只是这个TransactionStatus里的transaction属性为null。

创建事务小结

从以上分析可以看出,创建事务的步骤还是蛮多的;要判断当前是否已存在事务,还要根据不同的传播方式作出不同的响应。这里梳理了下逻辑,提供一张流程图作为参考:
在这里插入图片描述

事务提交

创建事务,执行完我们的业务逻辑后,我们需要提交这个事务。

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
	if (txInfo != null && txInfo.getTransactionStatus() != null) {
		// 委派给TransactionManager进行提交,我们这里是DataSourceTransactionManager
		txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
	}
}

// DataSourceTransactionManager#commit
public final void commit(TransactionStatus status) throws TransactionException {
    // 如果这个事务是已完成状态,说明哪里出错了,抛出异常
	if (status.isCompleted()) {
		throw new IllegalTransactionStateException(
				"Transaction is already completed - do not call commit or rollback more than once per transaction");
	}

	DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
	// 如果有rollback-only标记,就回滚
	if (defStatus.isLocalRollbackOnly()) {
		processRollback(defStatus, false);
		return;
	}

	if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
		processRollback(defStatus, true);
		return;
	}
    // 执行提交
	processCommit(defStatus);
}

processCommit

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
	try {
		boolean beforeCompletionInvoked = false;

		try {
			boolean unexpectedRollback = false;
			// 我们的DataSourceTransactionManager里,这个方法啥也没做
			prepareForCommit(status);
			// 执行事务拓展器(TransactionSynchronizationManager#synchronizations)里的beforeCommit方法
			triggerBeforeCommit(status);
			// 执行事务拓展器(TransactionSynchronizationManager#synchronizations)里的beforeCompletion方法
			triggerBeforeCompletion(status);
			beforeCompletionInvoked = true;

            // 如果有savepoint, 就是释放
            // 最终委派给数据库连接执行releaseSavepoint方法
            // 并将status里的savepoint属性设置为null
			if (status.hasSavepoint()) {
				unexpectedRollback = status.isGlobalRollbackOnly();
				status.releaseHeldSavepoint();
			}
			else if (status.isNewTransaction()) {
				unexpectedRollback = status.isGlobalRollbackOnly();
				// 真正提交
				// 委托为status里的transaction里的数据库连接进行提交
				doCommit(status);
			}
			else if (isFailEarlyOnGlobalRollbackOnly()) {
				unexpectedRollback = status.isGlobalRollbackOnly();
			}
            // UnexpectedRollbackException异常被捕获后
            // 执行完afterCompletion方法后,再向上抛出异常
			if (unexpectedRollback) {
				throw new UnexpectedRollbackException(
						"Transaction silently rolled back because it has been marked as rollback-only");
			}
		}
		catch ... // 执行事务扩展器里与异常相关的方法
		            // 除UnexpectedRollbackException类型的异常外,捕获到其他异常后会执行doRollbackOnCommitException。

		// 执行事务扩展器里的afterCommit方法
		try {
			triggerAfterCommit(status);
		}
		finally {
		    // 执行事务扩展器里的afterCompletion方法
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
		}

	}
	finally {
		cleanupAfterCompletion(status);
	}
}

事务提交方法里也有可能会进行回滚,这里的涉及到的回滚方法有:processRollbackdoRollbackOnCommitException

事务回滚

事务回滚的地方有多个:

  1. 执行业务过程中抛出异常,会通过completeTransactionAfterThrowing方法进行回滚。
  2. 在事务提交的校验逻辑里,发现这个事务被打上了rollback-only标记,会通过processRollback进行回滚。
  3. 在事务提交过程中发生异常,通过doRollbackOnCommitException进行回滚。
    我们从上往下一一解析。

completeTransactionAfterThrowing

执行业务过程中抛出异常,会调用该方法

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
	if (txInfo != null && txInfo.getTransactionStatus() != null) {
		// 如果抛出的异常符合我们在@Transactional里设置的rollbackOn才进行回滚
		// 否则还是提交
		if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
			try {
			    // 回滚,会委托到DataSourceTransactionManager#processRollback方法
				txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
			}
			...
		}
		else {
			try {
				txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
			}
			...
		}
	}
}

processRollback

在事务提交的校验逻辑里,发现这个事务被打上了rollback-only标记会调用到该方法。并且上面的completeTransactionAfterThrowing也是通过这个方法进行回滚。

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

		try {
		    // 调用事务拓展器里的beforeCompletion方法
			triggerBeforeCompletion(status);
            // 回滚到savepoint,最终委派给数据库连接进行回滚并是否savepoint
			if (status.hasSavepoint()) {
				status.rollbackToHeldSavepoint();
			}
			else if (status.isNewTransaction()) {
			    // 真正的回滚,委派给数据库连接进行回滚
				doRollback(status);
			}
			else {
			    // 沿用的事务会进入到这个分支
				if (status.hasTransaction()) {
					if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
					    // 设置status持有的ConnectionHoler的rollbackOnly为true
						doSetRollbackOnly(status);
					}
					else {
						...
					}
				}
				else {
					logger.debug("Should roll back transaction but cannot - no transaction available");
				}
				if (!isFailEarlyOnGlobalRollbackOnly()) {
					unexpectedRollback = false;
				}
			}
		}
		catch ...
        ...
	}
	finally {
		cleanupAfterCompletion(status);
	}
}

doRollbackOnCommitException

在事务提交过程中发生异常,通过doRollbackOnCommitException进行回滚。

private void doRollbackOnCommitException(DefaultTransactionStatus status, Throwable ex) throws TransactionException {
	try {
	    // 如果是新事务,直接执行回滚
		if (status.isNewTransaction()) {
		    // 真正的回滚,委派给数据库连接进行回滚
			doRollback(status);
		}
		else if (status.hasTransaction() && isGlobalRollbackOnParticipationFailure()) {
		    // 设置status持有的ConnectionHoler的rollbackOnly为true
			doSetRollbackOnly(status);
		}
	}
	catch ...
}

RollbackOnly

回滚过程中,我们看到有一个类似下面这样的判断:

if (!status.isNewTransaction()) {
    if (status.hasTransaction() && isGlobalRollbackOnParticipationFailure()) {
		doSetRollbackOnly(status);
	}
}

为什么会有这样的设置呢?因为我们方法的调用可能是嵌套的,但事务又是沿用的,在下一个@Transactional方法由于某种原因需要回滚时,我们并不能直接让这个事务进行回滚,我们需要通知调用方,这个事务被我标记为rollback-only了。提交其实也一样,在事务沿用时并不会执行commit动作。需要注意的是事务沿用,TransactionStatus还是会创建新的,但里面的transaction对象同一个。

事务恢复

创建事务里有几种情况是会将当前的事务对象挂起,再创建新的事务对象的。那么这些被挂起的事务对象又是怎么恢复的呢?
答案在processCommitprocessRollback这两个方法最后面的cleanupAfterCompletion

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    // 设置状态为完成
	status.setCompleted();
	// 清理TransactionSynchronizationManager里保存的ThreadLocal
	if (status.isNewSynchronization()) {
		TransactionSynchronizationManager.clear();
	}
	// 简单事务,将数据库连接的autoCommit重置为true并放回连接池
	if (status.isNewTransaction()) {
		doCleanupAfterCompletion(status.getTransaction());
	}
	// 如果有挂起
	if (status.getSuspendedResources() != null) {
	    // 恢复挂起的事务对象
		Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
		resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
	}
}

至此,Spring声明式注解已全部解析完啦~ 😆。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值