vue视频教程 二分类数据集 SpringApplication 测试用例 web开发 阿里巴巴 laravel postgresql inheritance boost 网站后台管理模板 collection框架的结构 etl数据 java解析json数组 svn查看历史版本 车载u盘 kubernetes架构 mysql更新 python编译环境 python做界面 python正则匹配数字 java对象和类 java程序 java学习流程 linux用户 javascript实例 登录界面html mounted 图片生成网址 3389扫描器 lol体验服转换器 混沌世界隐藏英雄密码 mpg格式转换 爱奇艺无法投屏 极限防守图 linux添加用户 迅捷屏幕录像工具 flash制作教程 ps画笔变成十字 dnf混沌行者加点
当前位置: 首页 > 学习教程  > 编程语言

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

2020/8/11 19:43:45 文章标签:

有没有觉得在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:
在这里插入图片描述


本文链接: http://www.dtmao.cc/news_show_100170.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?