Spring(二十一)Spring 声明式事务研究

有没有觉得在Spring 中使用事务很简单,完全不用了解事务,只知道需要加事务地方,加上 @Transactional 注解就好了。
是不是很简单?

但是,正因为封装的这么好,开发人员集中精力在业务开发上,那么很有可能忽略很多数据库一些特性以及觉得对 @Transactional 很了解,就是事务嘛。
以下几个问题可以思考下:

  1. 数据库事务隔离级别有哪些?
  2. @Transactional 操作事务隔离级别怎么对应上的?
  3. 嵌套事务怎么回事?
  4. 内部调用(this)事务方式,会生效吗?

带着这些问题,从本章开始抽丝剥茧,看看Spring如何实现生声明式事务的。
本文还是基于SpringBoot进行分析

SpringBoot tx入口

transaction 子包下面,有一个 @Configuration 注解的类TransactionAutoConfiguration

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

	@Bean
	@ConditionalOnMissingBean
	public TransactionManagerCustomizers platformTransactionManagerCustomizers(
			ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
		return new TransactionManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
	}

	@Configuration
	@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
	public static class TransactionTemplateConfiguration {

		private final PlatformTransactionManager transactionManager;

		public TransactionTemplateConfiguration(PlatformTransactionManager transactionManager) {
			this.transactionManager = transactionManager;
		}

		@Bean
		@ConditionalOnMissingBean
		public TransactionTemplate transactionTemplate() {
			return new TransactionTemplate(this.transactionManager);
		}

	}

	@Configuration
	@ConditionalOnBean(PlatformTransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {

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

		}

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

		}

	}

}

上面Configuration将在Spring Boot项目启动时加载。

  1. @ConditionalOnClass 开头接口将依据 类路径下是否有 PlatformTransactionManager 类,决定是否加载该配置类。当引入 spring-tx 包后,这一步条件将通过
  2. @AutoConfigureAfter 将限制,需要在 JtaAutoConfigurationHibernateJpaAutoConfigurationDataSourceTransactionManagerAutoConfigurationNeo4jDataAutoConfiguration 加载后再加载 当前类。
  3. @EnableConfigurationProperties(TransactionProperties.class) 声明数据绑定对象。

其实Spring 的中事务有两种实现方式,一种是Proxy,即代理的方式。另一种则是 AspectJ方式。
两者区别简单来说就是如下几点:

  1. AspectJ的功能更加全面和强大。支持全部的Pointcut类型。
  2. 毕竟Spring作为一个以集成起家的框架,在设计Spring AOP的时候也是为了减轻开发人员负担而做了不少努力的。它提供的开箱即用(Out-of-the-box)的众多AOP功能让很多开发人员甚至都不知道什么是AOP
  3. Spring AOP: 基于代理(Proxying) AspectJ: 基于字节码操作(Bytecode Manipulation)
    如果想使用 AspectJ 方式,则需要制定aspectJ的agent。

本文主要围绕Proxy类型事务进行研究,当然两种方式,博主都有具体例子:
AspectJ
Proxy

上面SpringBoot的auto-config 经过对bean和class存在性判断后,其实主要起作用的bean为 @EnableTransactionManagement(proxyTargetClass = false)

EnableTransactionManagement

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	...
}

再看 具体的 TransactionManagementConfigurationSelector 类:

	@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() {
		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
	}

以Proxy分析的话,EnableTransactionManagement 引入了两个类:AutoProxyRegistrarProxyTransactionManagementConfiguration

AutoProxyRegistrar 主要为配置AOP代理模式,如果有则不需要配置。

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
		for (String annType : annTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				if (mode == AdviceMode.PROXY) {
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}

AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); 中,如果系统已经注册过AOP代理工厂了(例如直接配置SpringAop),则强行更改其代理模式(proxyTargetClass)为 true,即强行使用cglib代理。

ProxyTransactionManagementConfiguration
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
	
	// 声明一个Advisor
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}
	
	// 用于解析注解参数
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}
	// 声明一个拦截器 即Advice
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

Spring Transaction 工具Bean类已经都定义完了,这么少吗?
确实是的,如果看过博主前面分析Spring Aop原理文章,则能大概猜出Spring Transaction 是利用Aop进行方法级别切入,并在其中配置事务操作的。

BeanFactoryTransactionAttributeSourceAdvisor

先看看 BeanFactoryTransactionAttributeSourceAdvisor 的类结构:
在这里插入图片描述
BeanFactoryTransactionAttributeSourceAdvisor 中有一个 TransactionAttributeSourcePointcut 字段,即 Advisor有PointCut拦截,还有 具体切入点的 MethodInterceptor
pointcut内部的matches方法又是如何实现的呢?

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
				PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
				PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
			return false;
		}
		// 获取BeanFactoryTransactionAttributeSourceAdvisor 中传入的TransactionAttributeSource
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 即当方法有Transaction注解时候,需要spring aop进行切入
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

getTransactionAttribute 方法比较容易理解,感兴趣可以自行查看。

TransactionInterceptor

如果匹配上了,怎么处理呢?具体组装逻辑则是通过Spring Aop进行组装。首先进入DynamicAdvisedInterceptorintercept 方法通用AOP拦截,而后根据不同拦截器链,调用到 TransactionInterceptorinvoke 方法:

	@Override
	@Nullable
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		// 得出当前类
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

invokeWithinTransaction 方法如下:

	protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

		// If the transaction attribute is null, the method is non-transactional.
		// 获取 TransactionAttributeSource  
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 获取注解参数
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		// 决定使用哪个事务管理器,这个可以在注解上定义 默认事务管理器为 :DataSourceTransactionManager,如果要做主从库等,可以自己定义后修改
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		// 获取方法完整名字
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
		
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// 标准事务管理
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
		// 编程式事务管理,或者没有声明注解,直接执行,但是会记录错误信息。
			final ThrowableHolder throwableHolder = new ThrowableHolder();

			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
					TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
					try {
						return invocation.proceedWithInvocation();
					}
					catch (Throwable ex) {
						if (txAttr.rollbackOn(ex)) {
							// A RuntimeException: will lead to a rollback.
							if (ex instanceof RuntimeException) {
								throw (RuntimeException) ex;
							}
							else {
								throw new ThrowableHolderException(ex);
							}
						}
						else {
							// A normal return value: will lead to a commit.
							throwableHolder.throwable = ex;
							return null;
						}
					}
					finally {
						cleanupTransactionInfo(txInfo);
					}
				});

				// Check result state: It might indicate a Throwable to rethrow.
				if (throwableHolder.throwable != null) {
					throw throwableHolder.throwable;
				}
				return result;
			}
			catch (ThrowableHolderException ex) {
				throw ex.getCause();
			}
			catch (TransactionSystemException ex2) {
				if (throwableHolder.throwable != null) {
					logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
					ex2.initApplicationException(throwableHolder.throwable);
				}
				throw ex2;
			}
			catch (Throwable ex2) {
				if (throwableHolder.throwable != null) {
					logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
				}
				throw ex2;
			}
		}
	}

其实看上述方法结构,也大概有了理解了,基本的事务操作如下:

getConnection();
try{
	doSomeThing();
}catch(Exception e){
	rollback();
}finally{
	reset();
}
commit();
  1. 解析注解,获取注解声明的事务管理器
  2. 判断事务管理器类型,决定是否走通用声明式事务处理方法
  • 没有声明事务,或者使用函数式事务 CallbackPreferringPlatformTransactionManager ,则直接往下执行,并且记录相应的 错误
  • 声明事务,则走try{}catch{}finally{} 模板逻辑处。

下面对这几个快方法进行具体方法

数据准备阶段

TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Spring 事务管理中,有 多种可选的参数:

public @interface Transactional {
	// 事务管理器
	@AliasFor("transactionManager")
	String value() default "";
	// 事务管理器别名
	@AliasFor("value")
	String transactionManager() default "";
	// 事务传递属性,默认是 REQUIRED
	Propagation propagation() default Propagation.REQUIRED;
	// 事务隔离级别
	Isolation isolation() default Isolation.DEFAULT;
	// 事务超时时间
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
	// 判断事务是否只读
	boolean readOnly() default false;
	// 导致事务回滚的异常类数组,只能是 Throwable 子类
	Class<? extends Throwable>[] rollbackFor() default {};
	// 异常时抛出错误名
	String[] rollbackForClassName() default {};	
	// 不会导致事务回滚的异常类
Class<? extends Throwable>[] noRollbackFor() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
}

其他的不用过多说,难以理解的为 propagationisolationrollbackFor
当然对于 isolation 事务隔离级别,则是说明当前执行回话事务隔离级别,和数据库中对应的。
propagation 为事务传播特性,主要有以下几种:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前有事务,则加入,否则新建事务
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前有事务,则加入,否则不建立新事务
  • TransactionDefinition.PROPAGATION_MANDATORY:如果当前有事务,则加入,否则报错
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建新事务;如果当前有事务,则暂停。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:如果当前事务存在,那么会暂停当前事务,并且方法内部使用非事务方式运行
  • TransactionDefinition.PROPAGATION_NEVER:不允许有事务,如果当前事务已经存在,则报错
  • TransactionDefinition.PROPAGATION_NESTED:如果存在事务,则在嵌套事务执行,没有事务,则新建事务。
    前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
    它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)

在这里插入图片描述
图片转自: https://blog.csdn.net/yanxin1213/article/details/100582643

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

		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
			// 获取事务状态
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

最开始获取事务名称,而后获取事务状态:

	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
	// 获取当前线程所拥有连接
		Object transaction = doGetTransaction();

		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();

		if (definition == null) {
			// Use defaults if no transaction definition given.
			definition = new DefaultTransactionDefinition();
		}

		if (isExistingTransaction(transaction)) {
		// 如果是已经存在的事务,则根据传递级别 propagation去进行不同操作
		// 判断方式就是当前线程是否已经有事务,有就说明已有事务
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		 以下处理,都是基于没有事务进行

		// Check definition settings for new transaction.
		// 判断超时时间
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// No existing transaction found -> check propagation behavior to find out how to proceed.
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
		// 如果是 PROPAGATION_MANDATORY 类型传递,但是当前没有事务,就报错。
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
				// 如果是这三种 PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
				// 暂停当前事务,并获取当前异步事务
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
				// 当前事务,是否需要暂停
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				// 创建一个事务状态
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				// 使用当前连接,配置当前连接,设置autoCommit,timeout,去preparestatement等等。
				doBegin(transaction, definition);
				// 如果当前操作是首次线程操作,那么需要设置当前线程一些值
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// 无事务
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + definition);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			// 设置一些 当前线程的状态TransactionSynchronizationManager
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}

上面获取完事务状态后,调用 prepareTransactionInfo 构造出一份 TransactionInfo 返回。

执行方法阶段

执行方法,是直接调用下一次拦截,

retVal = invocation.proceedWithInvocation();

即默认 事务切面会优先于 @Advice 注解产生切面。最终整个调用方法栈,即如果其他切面逻辑报错,也会导致其回滚。

异常处理

当栈进栈出之后,如果报错,则会进入catch块:

			catch (Throwable ex) {
				// target invocation exception
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}

看看 completeTransactionAfterThrowing 方法:

	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);
			}
			// 如果配置的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;
				}
			}
		}
	}

而回滚之后,就会利用上面Spring 中定义的事务传递进行选择了。
回滚操作

	@Override
	public final void rollback(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;
		processRollback(defStatus, false);
	}

主要工作在 processRollback:

	private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
		try {
		// 获取配置的开关,如果是未期待错误处理
			boolean unexpectedRollback = unexpected;

			try {
			// 如果有配置 TransactionSynchronization 的 beforeCompletion 操作,则会触发。
				triggerBeforeCompletion(status);

				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Rolling back transaction to savepoint");
					}
						// 如果有保存点,则会执行 rollbackToHeldSavepoint 进行单独回滚,回滚到savepoint,并将savepint清空
					status.rollbackToHeldSavepoint();
				}
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction rollback");
					}
					// 普通回滚,获取本次Connection直接回滚
					doRollback(status);
				}
				else {
				// 一次大事务
					// Participating in larger transaction
					if (status.hasTransaction()) {
						if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
							}
							doSetRollbackOnly(status);
						}
						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;
			}
			// 触发TransactionSynchronization 的 afterCompletion 操作,则会触发。
			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 {
		// 清除信息,包括DefaultTransactionStatus 和 当前线程信息状态,放回连接等
			cleanupAfterCompletion(status);
		}
	}
清除信息

finally块中有一个方法,无论成功还是失败,都会执行

cleanupTransactionInfo(txInfo);

主要目的为设置当前事务线程的TransactionInfo信息到ThreadLocal中。

提交事务

如果整个过程没有报错,那么就会执行:
commitTransactionAfterReturning(txInfo);
来执行提交事务操作。
具体看 AbstractPlatformTransactionManagercommit 方法:

	@Override
	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()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}
		// 设置了globeOnly,也会回滚。并会设置不期待的回滚
		if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
			}
			processRollback(defStatus, true);
			return;
		}
		// 执行事务提交动作
		processCommit(defStatus);
	}

大概代码流程,都在代码中带有注释,对于具体事务提交都当做,却做了很多事:

	private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
		// 设置标记变量
			boolean beforeCompletionInvoked = false;
			try {
				boolean unexpectedRollback = false;
				prepareForCommit(status);
				// 触发TransactionSynchronization 中 beforeCommit 操作
				triggerBeforeCommit(status);
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;

				if (status.hasSavepoint()) {
				// 如果有savepoint
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					// 释放安全点
					status.releaseHeldSavepoint();
				}
				else if (status.isNewTransaction()) {
				// 新事务
					if (status.isDebug()) {
						logger.debug("Initiating transaction commit");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					// 具体提交事务操作,就是connection.commit
					doCommit(status);
				}
				else if (isFailEarlyOnGlobalRollbackOnly()) {
					unexpectedRollback = status.isGlobalRollbackOnly();
				}

				// Throw UnexpectedRollbackException if we have a global rollback-only
				// marker but still didn't get a corresponding exception from commit.
				if (unexpectedRollback) {
				// 如果被标记为rollback-only,则也要抛出异常,就算commit了,也要跑出来
					throw new UnexpectedRollbackException(
							"Transaction silently rolled back because it has been marked as rollback-only");
				}
			}
			catch (UnexpectedRollbackException ex) {
				// can only be caused by doCommit
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
				throw ex;
			}
			catch (TransactionException ex) {
				// can only be caused by doCommit
				if (isRollbackOnCommitFailure()) {
					doRollbackOnCommitException(status, ex);
				}
				else {
					triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				}
				throw ex;
			}
			catch (RuntimeException | Error ex) {
				if (!beforeCompletionInvoked) {
					triggerBeforeCompletion(status);
				}
				doRollbackOnCommitException(status, ex);
				throw ex;
			}

			// Trigger afterCommit callbacks, with an exception thrown there
			// propagated to callers but the transaction still considered as committed.
			try {
			// 触发 TransactionSynchronization 的 afterCommit 操作
				triggerAfterCommit(status);
			}
			finally {
			// 触发 TransactionSynchronization 的 afterCompletion 操作
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
			}

		}
		finally {
		// 清理相关信息
			cleanupAfterCompletion(status);
		}
	}

总结

整个事务逻辑,简略来说就是如下面的伪代码,而Spring在此基础上丰富了事务操作,并且简化了编程,我们只需要一个注解就可以完成:

getConnection();
try{
	doSomeThing();
}catch(Exception e){
	rollback();
}finally{
	reset();
}
commit();

其中,Spring Transaction提供了事务接入点,可对事务执行阶段进行通知,当然可以自行增加相关组件实现。

觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,一起研究Spring:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值