前提

  1. 本文代码基于SpringBoot的2.1.1.RELEASE版本。
  2. spring事务是基于spring aop,而spring aop是基于spring ioc,所以在学习spring事务之前,要先了解bin17:SpringBoot源码之旅——IoC容器和bin17:SpringBoot源码之旅——AOP。

概述

概括来讲,事务是一个由有限操作集合组成的逻辑单元。事务操作包含两个目的,数据一致以及操作隔离。数据一致是指事务提交时保证事务内的所有操作都成功完成,并且更改永久生效;事务回滚时,保证能够恢复到事务执行之前的状态。操作隔离则是指多个同时执行的事务之间应该相互独立,互不影响。

事务是一个比较广泛的概念,事务管理资源除了我们熟知的数据库外,还可以包含消息队列、文件系统等。当然,一般来说,我们说的事务单指“数据库事务”。接下来我们会以MySQL数据库、Spring声明式事务为主要研究对象,但是很多事务概念、接口抽象和实现方式同时适用于其他情况。


准备

1,ACID,隔离级别,传播机制

可能是最漂亮的Spring事务管理详解 - 掘金juejin.im


2,AOP

声明式事务的实现就是通过AOP环绕增强的方式,在目标方法执行之前开启事务,在目标方法执行之后提交或者回滚事务。

TransactionInterceptor


springboot 源码解析 pdf springboot aop源码_spring


对于基于JDK接口动态代理的AOP事务增强来说,由于接口的方法都必须是public的,这就要求实现类的实现方法也必须是public的(不能是protected、private等),同时不能使用static修饰符。所以,可以实施接口动态代理的方法只能是public或public final修饰符的方法,其他方法不能被动态代理,相应地也就不能实施AOP增强。

基于CGLib字节码动态代理的方案是通过扩展被增强类,动态创建其子类的方式进行AOP增强植入的。由于使用final、static、private修饰符的方法都不能被子类覆盖,相应的这些方法将无法实施AOP增强。

这些不能被spring事务增强的特殊方法并非就不工作在事务环境中,由于spring事务管理的传播级别,这些特殊方法和可被spring事务增强的方法的唯一区别在于是否可以主动启动一个新事务,如果这些特殊方法被无事务上下文的方法调用,则它们就工作在无事务上下文中,反之,如果被具有事务上下文的方法调用,则它们就工作在事务上下文中。

3,事务抽象

TransactionDefinition:用于描述事务的隔离级别、超时时间、是否为只读事务和事务传播规则等控制事务具体行为的事务属性。

TransactionStatus:代表一个事务的具体运行状态。事务管理器可以通过该接口获取事务运行期的状态信息,也可以通过该接口间接地回滚事务,它相比于在抛出异常时回滚事务的方式更具可控性。

PlatformTransactionManager:PlatformTransactionManager根据TransactionDefinition提供的事务属性配置信息创建事务,并用TransactionStatus描述这个激活事务的状态。


springboot 源码解析 pdf springboot aop源码_spring_02


4,ThreadLocal

通过ThreadLocal,多个操作在同一个线程中共享数据库connection,不同线程互不影响,解决了线程安全问题。

在相同线程中进行相互嵌套调用的事务方法工作在相同的事务中。如果这些相互嵌套调用的方法工作在不同的线程中,则不同线程下的事务方法工作在独立的事务中。


GO!

AOP切面织入生成代理对象的过程,当Bean方法通过代理对象调用时,会触发对应的AOP增强拦截器,声明式事务是一种环绕增强,对应接口为MethodInterceptor,事务增强对该接口的实现为TransactionInterceptor


springboot 源码解析 pdf springboot aop源码_springaop事务逻辑原理_03


事务拦截器TransactionInterceptororg.springframework.transaction.interceptor.TransactionInterceptor#invoke方法中,


public Object invoke(MethodInvocation invocation) throws Throwable {
	Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
	Method var10001 = invocation.getMethod();
	invocation.getClass();
	return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
}


通过调用父类TransactionAspectSupportorg.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction方法进行事务处理,该方法支持声明式事务和编程式事务


protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
	// 查询目标方法事务属性、确定事务管理器、构造连接点标识(用于确认事务名称)
	TransactionAttributeSource tas = this.getTransactionAttributeSource();
	TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
	PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
	String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
	Object result;
	if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
		TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder();

		try {
			result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, (status) -> {
				TransactionAspectSupport.TransactionInfo txInfo = this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

				Object var9;
				try {
					Object var8 = invocation.proceedWithInvocation();
					return var8;
				} catch (Throwable var13) {
					if (txAttr.rollbackOn(var13)) {
						if (var13 instanceof RuntimeException) {
							throw (RuntimeException)var13;
						}

						throw new TransactionAspectSupport.ThrowableHolderException(var13);
					}

					throwableHolder.throwable = var13;
					var9 = null;
				} finally {
					this.cleanupTransactionInfo(txInfo);
				}

				return var9;
			});
			if (throwableHolder.throwable != null) {
				throw throwableHolder.throwable;
			} else {
				return result;
			}
		} catch (TransactionAspectSupport.ThrowableHolderException var19) {
			throw var19.getCause();
		} catch (TransactionSystemException var20) {
			if (throwableHolder.throwable != null) {
				this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
				var20.initApplicationException(throwableHolder.throwable);
			}

			throw var20;
		} catch (Throwable var21) {
			if (throwableHolder.throwable != null) {
				this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
			}

			throw var21;
		}
	} else {
		// 事务获取
		TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
		result = null;

		try {
			// 通过回调执行目标方法
			result = invocation.proceedWithInvocation();
		} catch (Throwable var17) {
			// 目标方法执行抛出异常,根据异常类型执行事务提交或者回滚操作
			this.completeTransactionAfterThrowing(txInfo, var17);
			throw var17;
		} finally {
			// 清理当前线程事务信息
			this.cleanupTransactionInfo(txInfo);
		}

		// 标方法执行成功,提交事务
		this.commitTransactionAfterReturning(txInfo);
		return result;
	}
}


在讲Spring事务抽象时,有提到事务抽象的核心接口为PlatformTransactionManager,它负责管理事务行为,包括事务的获取、提交和回滚。在invokeWithinTransaction方法中,我们可以看到createTransactionIfNecessarycommitTransactionAfterReturningcompleteTransactionAfterThrowing都是针对该接口编程,并不依赖于特定事务管理器,这里是对Spring事务抽象的实现。

提到事务传播机制时,我们经常提到一个条件“如果当前已有事务”,那么Spring是如何知道当前是否已经开启了事务呢?在AbstractPlatformTransactionManager中是这样做的

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction


public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
	Object transaction = this.doGetTransaction();
	boolean debugEnabled = this.logger.isDebugEnabled();
	if (definition == null) {
		definition = new DefaultTransactionDefinition();
	}

	if (this.isExistingTransaction(transaction)) {
		return this.handleExistingTransaction((TransactionDefinition)definition, transaction, debugEnabled);
	} else if (((TransactionDefinition)definition).getTimeout() < -1) {
		throw new InvalidTimeoutException("Invalid transaction timeout", ((TransactionDefinition)definition).getTimeout());
	...
}


注意getTransaction方法是final的,无法被子类覆盖,保证了获取事务流程的一致和稳定。抽象方法doGetTransaction获取当前事务对象,方法isExistingTransaction判断当前事务对象是否存在活跃事务,具体逻辑由特定事务管理器实现,看下我们使用最多的DataSourceTransactionManager对应的实现

org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction


protected Object doGetTransaction() {
	DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
	txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
	ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
	txObject.setConnectionHolder(conHolder, false);
	return txObject;
}


org.springframework.transaction.support.TransactionSynchronizationManager#getResource


public static Object getResource(Object key) {
	Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
	Object value = doGetResource(actualKey);
	if (value != null && logger.isTraceEnabled()) {
		logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
	}

	return value;
}


org.springframework.transaction.support.TransactionSynchronizationManager#doGetResource


private static Object doGetResource(Object actualKey) {
	Map<Object, Object> map = (Map)resources.get();
	if (map == null) {
		return null;
	} else {
		Object value = map.get(actualKey);
		if (value instanceof ResourceHolder && ((ResourceHolder)value).isVoid()) {
			map.remove(actualKey);
			if (map.isEmpty()) {
				resources.remove();
			}

			value = null;
		}

		return value;
	}
}


TransactionSynchronizationManager


springboot 源码解析 pdf springboot aop源码_spring_04


TransactionSynchronizationManager通过ThreadLocal对象在当前线程记录了resourcessynchronizations属性。resources是一个HashMap,用于记录当前参与事务的事务资源,方便进行事务同步,在DataSourceTransactionManager的例子中就是以dataSource作为key,保存了数据库连接,这样在同一个线程中,不同的方法调用就可以通过dataSource获取相同的数据库连接,从而保证所有操作在一个事务中进行。

synchronizations属性是一个TransactionSynchronization对象的集合,AbstractPlatformTransactionManager类中定义了事务操作各个阶段的调用流程,以事务提交为例

org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit


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

		try {
			boolean unexpectedRollback = false;
			this.prepareForCommit(status);
			this.triggerBeforeCommit(status);
			this.triggerBeforeCompletion(status);
			beforeCompletionInvoked = true;
	...

}


我们可以看到,有很多trigger前缀的方法,这些方法用于在事务操作的各个阶段触发回调,从而可以精确控制在事务执行的不同阶段所要执行的操作,这些回调实际上都通过TransactionSynchronizationUtils来实现,它会遍历TransactionSynchronizationManager#synchronizations集合中的TransactionSynchronization对象,然后分别触发集合中各个元素对应方法的调用。

TransactionSynchronization


springboot 源码解析 pdf springboot aop源码_spring_05


最后,流程图


springboot 源码解析 pdf springboot aop源码_springboot 手动提交事务_06


demo

https://github.com/BinGithub2015/zhihu/tree/master/demogithub.com