Spring源码学习(十五)-- 事务底层源码解析

今天我们主要来学习一下Spring事务的源码解析,主要讲的是Spring的申明式事务的讲解。申明式事务管理: 基于Spring AOP实现。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。申明式事务管理不需要入侵代码,通过@Transactional就可以进行事务操作,且大部分业务都可以满足,推荐使用。

源码解析入口

@EnableTransactionManagement工作原理

使用EnableTransactionManagement注解可以开启Spring事务,而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导入了TransactionManagementConfigurationSelector

该类实现了ImportSelector接口,通过覆写selectImports()方法,手动将java类注册到Spring框架的IOC容器中。

	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				// 默认是PROXY
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				// 表示不用动态代理技术,用ASPECTJ技术,比较麻烦了
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

向Spring容器中添加了两个Bean:

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

首先看一下AutoProxyRegistrar,实现了ImportBeanDefinitionRegistrar

通过这个类,Spring会将InfrastructureAdvisorAutoProxyCreator.class注册到IOC容器

 InfrastructureAdvisorAutoProxyCreator的类图:

InfrastructureAdvisorAutoProxyCreator继承了AbstractAdvisorAutoProxyCreator, AbstractAdvisorAutoProxyCreator非常强大以及重要,只要Spring容器中存在这个类型的Bean,就相当于开启了AOP,AbstractAdvisorAutoProxyCreator实际上就是一个BeanPostProcessor,所以在创建某个Bean时,就会进入到它对应的生命周期方法中,在某个Bean初始化之后,会调用父类AbstractAutoProxyCreator的postProcessAfterInitialization方法(上篇文章AOP有学习到)

注意:InfrastructureAdvisorAutoProxyCreator会去查找spring容器中的Advisor但是不是解析@Aspect等注解。

@Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

/**  Wrap the given bean if necessary  
  *  对bean进行包装,其实就是创建代理对象
  */
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        
        // 省略。。。。
        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 创建代理,jdk动态代理或者cglib代理
            Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

    }

上述代码的作用就是,Spring在bean初始化之后,会判断该bean是否需要创建一个代理对象,如果需要,就会使用jdk动态代理或者cglib创建一个代理类(上篇AOP源码的文章有分析)。

注册的另外一个ProxyTransactionManagementConfiguration是一个配置类,它又定义了另外三个bean:

  1. BeanFactoryTransactionAttributeSourceAdvisor:一个Advisor
  2. AnnotationTransactionAttributeSource:相当于BeanFactoryTransactionAttributeSourceAdvisor中的Pointcut
  3. TransactionInterceptor:相当于BeanFactoryTransactionAttributeSourceAdvisor中的Advice

AnnotationTransactionAttributeSource就是用来判断某个类上是否存在@Transactional注解,或者判断某个方法上是否存在@Transactional注解的。
TransactionInterceptor就是代理逻辑,当某个类中存在@Transactional注解时,到时就产生一个代理对象作为Bean,代理对象在执行某个方法时,最终就会进入到TransactionInterceptor的invoke()方法。

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	// 事务增强
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		// BeanFactoryTransactionAttributeSourceAdvisor内部定义了一个Pointcut,Pointcut在匹配时会用到transactionAttributeSource来解析类或方法上是否存在@Transactional
		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() {
		// AnnotationTransactionAttributeSource中构造了一个SpringTransactionAnnotationParser,用来解析类或方法上的@Transactional注解
		return new AnnotationTransactionAttributeSource();
	}

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

}

核心方法:transactionAdvisor()事务织入

定义了一个advisor,设置事务属性、设置事务拦截器TransactionInterceptor、设置顺序。核心就是事务拦截器TransactionInterceptor。

TransactionInterceptor使用通用的spring事务基础架构实现“声明式事务”,继承自TransactionAspectSupport类(该类包含与Spring的底层事务API的集成),实现了MethodInterceptor接口。spring类图如下:

 事务拦截器的拦截功能就是依靠实现了MethodInterceptor接口,熟悉spring的同学肯定很熟悉MethodInterceptor了,这个是spring的方法拦截器。

Spring事务基本执行原理

一个Bean在执行Bean的创建生命周期时,会经过InfrastructureAdvisorAutoProxyCreator的初始化后的方法,会判断当前当前Bean对象是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,匹配逻辑为判断该Bean的类上是否存在@Transactional注解,或者类中的某个方法上是否存在@Transactional注解,如果存在则表示该Bean需要进行动态代理产生一个代理对象作为Bean对象。

该代理对象在执行某个方法时,会再次判断当前执行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配则执行该Advisor中的TransactionInterceptor的invoke()方法,执行基本流程为:

  1. 利用所配置的PlatformTransactionManager事务管理器新建一个数据库连接
  2. 修改数据库连接的autocommit为false
  3. 执行MethodInvocation.proceed()方法,简单理解就是执行业务方法,其中就会执行sql
  4. 如果没有抛异常,则提交
  5. 如果抛了异常,则回滚
	@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...
		// 调用父类TransactionAspectSupport的 invokeWithinTransaction方法
		return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
			@Override
			@Nullable
			// 执行后续的Interceptor,以及被代理的方法
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
			@Override
			public Object getTarget() {
				return invocation.getThis();
			}
			@Override
			public Object[] getArguments() {
				return invocation.getArguments();
			}
		});
	}

TransactionInterceptor复写MethodInterceptor接口的invoke方法,并在invoke方法中调用了父类TransactionAspectSupport的invokeWithinTransaction()方法,源码如下:

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

		// If the transaction attribute is null, the method is non-transactional.
		// TransactionAttribute就是@Transactional中的配置
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 获取到当前方法或类上的@Transactional注解的信息
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

		// 得到一个TransactionManager
		final TransactionManager tm = determineTransactionManager(txAttr);

		// ReactiveTransactionManager用得少,并且它只是执行方式是响应式的,原理流程和普通的是一样的
		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
			boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
			boolean hasSuspendingFlowReturnType = isSuspendingFunction &&
					COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName());
			if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
				throw new IllegalStateException("Coroutines invocation not supported: " + method);
			}
			CoroutinesInvocationCallback corInv = (isSuspendingFunction ? (CoroutinesInvocationCallback) invocation : null);

			ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
				Class<?> reactiveType =
						(isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType());
				ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
				if (adapter == null) {
					throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
							method.getReturnType());
				}
				return new ReactiveTransactionSupport(adapter);
			});

			InvocationCallback callback = invocation;
			if (corInv != null) {
				callback = () -> CoroutinesUtils.invokeSuspendingFunction(method, corInv.getTarget(), corInv.getArguments());
			}
			Object result = txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, (ReactiveTransactionManager) tm);
			if (corInv != null) {
				Publisher<?> pr = (Publisher<?>) result;
				return (hasSuspendingFlowReturnType ? KotlinDelegate.asFlow(pr) :
						KotlinDelegate.awaitSingleOrNull(pr, corInv.getContinuation()));
			}
			return result;
		}

		// 转化为PlatformTransactionManager
		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		// joinpoint的唯一标识
		// 根据当前执行的类中的某个方法以及@Transactional注解的信息生成一个唯一标志,这个标记会用来作为事务名
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		// CallbackPreferringPlatformTransactionManager表示拥有回调功能的PlatformTransactionManager,也不常用
		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			// 如果有必要就创建事务,这里就涉及到事务传播机制的实现了
			// TransactionInfo表示一个逻辑事务,比如两个逻辑事务属于同一个物理事务
			// 创建事务,并得到事务信息,后面需要事务信息用来进行提交或回滚,这里不一定创建了事务,也可能延用了已存在的事务
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, 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.
				// 执行下一个Interceptor或被代理对象中的方法
				// 执行业务方法逻辑
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				// 出现异常的情况下,如果异常需要rollback,则回滚,否则则会提交
				completeTransactionAfterThrowing(txInfo, ex);
				// 出现异常后会先执行finally中的方法逻辑在抛出当前异常
				throw ex;
			}
			finally {
				// 清除ThreadLocal中的事务信息
				cleanupTransactionInfo(txInfo);
			}

			if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				// Set rollback-only in case of Vavr failure matching our rollback rules...
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}

			// 提交事务
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			Object result;
			final ThrowableHolder throwableHolder = new ThrowableHolder();

			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
					TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
					try {
						Object retVal = invocation.proceedWithInvocation();
						if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
							// Set rollback-only in case of Vavr failure matching our rollback rules...
							retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
						}
						return retVal;
					}
					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);
					}
				});
			}
			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;
			}

			// Check result state: It might indicate a Throwable to rethrow.
			if (throwableHolder.throwable != null) {
				throw throwableHolder.throwable;
			}
			return result;
		}
	}

获取事务信息

接下来进入createTransactionIfNecessary方法查看事务的创建过程。

	protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

		// If no name specified, apply method identification as transaction name.
		// 事务的名字
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}

		// 事务状态对象
		// 每个逻辑事务都会创建一个TransactionStatus,但是TransactionStatus中有一个属性代表当前逻辑事务底层的物理事务是不是新的
		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);
	}

进入AbstractPlatformTransactionManager.getTransaction()方法

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

		// Use defaults if no transaction definition given.
		// TransactionDefinition就是TransactionAttribute,就是@Transactional注解信息
		// 表示一个事务的定义,通过@Transactional注解也就是在定义一个事务
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

		// 获取一个事务对象,每次都会生成一个DataSourceTransactionObject,而重点是这个对象中是否已经存在一个数据库连接
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();

		// transaction.getConnectionHolder().isTransactionActive()
		// 如果已经存在一个数据库连接,表示当前线程已经存在一个事务
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			// 存在事务的情况下,按不同的传播级别进行处理
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		// timeout如果为-1,表示没有时间限制
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}

		// 当前线程还不存在事务
		// No existing transaction found -> check propagation behavior to find out how to proceed.
		// 当前不存在事务,传播机制=MANDATORY(支持当前事务,没事务报错),报错
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		// 当前不存在事务,传播机制=REQUIRED/REQUIRED_NEW/NESTED,这三种情况,需要新开启事务,且加上事务同步
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			// 没有事务需要挂起,不过TransactionSynchronization有可能需要挂起
			// suspendedResources表示当前线程被挂起的资源持有对象(数据库连接、TransactionSynchronization)
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				// 开启事务后,transaction中就会有数据库连接了,并且isTransactionActive为true
				// 并返回TransactionStatus对象,该对象保存了很多信息,包括被挂起的资源
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// 不会doBegin,不会真的开启事务,也就是不会把Connection的autoCommit设置为false,sql没有在事务中执行
			// 当前不存在事务当前不存在事务,且传播机制=PROPAGATION_SUPPORTS/PROPAGATION_NOT_SUPPORTED/PROPAGATION_NEVER,这三种情况,创建“空”事务:没有实际事务,但可能是同步。
			//警告:定义了隔离级别,但并没有真实的事务初始化,隔离级别被忽略有隔离级别但是并没有定义实际的事务初始化,有隔离级别但是并没有定义实际的事务初始化,
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + def);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}

 继续向里面走,看核心方法DataSourceTransactionManager.doGetTransaction(),这里就是创建了一个DataSourceTransactionObject对象

	@Override
	protected Object doGetTransaction() {
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		// 是否允许嵌套事务,默认是允许的,在DataSourceTransactionManager无参构造方法中进行了设置
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		// 从当前线程ThreadLocal中获取当前DataSource所对应的数据库连接,可能为null
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

回到流程中去,到 startTransaction方法

	private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

		// 开启的这个事务的状态信息:
		// 事务的定义、用来保存数据库连接的对象、是否是新事务,是否是新的TransactionSynchronization
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		// 开启事务,获得新的Connection对象
		doBegin(transaction, definition);
		// 初始化TransactionSynchronizationManager中的属性
		prepareSynchronization(status, definition);
		return status;
	}

  doBegin方法,开启一个事务

	@Override
	protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {

			// 如果当前线程中所使用的DataSource还没有创建过数据库连接,就获取一个新的数据库连接
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				// isSynchronizedWithTransaction 我的理解,表示连接是否和事务同步,表示每开启一个事务就从DataSource中获取一个连接
				// 默认是false,所以在开启事务时,除非当前事务对象中还没有数据库连接才会从DataSource中去获取一个连接
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				// 设置为newConnectionHolder为true
				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());

			// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
			// so we don't want to do it unnecessarily (for example if we've explicitly
			// configured the connection pool to set it already).
			// 设置autocommit为false
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}

			prepareTransactionalConnection(con, definition);
			txObject.getConnectionHolder().setTransactionActive(true);

			// 设置数据库连接的过期时间
			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			// Bind the connection holder to the thread.
			if (txObject.isNewConnectionHolder()) {
				// 把新生成的数据库连接设置到当前线程的TheadLocal中进行缓存
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}

		catch (Throwable ex) {
			if (txObject.isNewConnectionHolder()) {
				DataSourceUtils.releaseConnection(con, obtainDataSource());
				txObject.setConnectionHolder(null, false);
			}
			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
		}
	}

在这里插入图片描述

 

源码分成了2条处理线,

(1).当前已存在事务:isExistingTransaction()判断是否存在事务,存在事务handleExistingTransaction()根据不同传播机制不同处理

(2).当前不存在事务: 不同传播机制不同处理

commit提交事务

在这里插入图片描述 SqlSessionSynchronization是SqlSessionUtils的一个内部类,继承自TransactionSynchronizationAdapter抽象类,实现了事务同步接口TransactionSynchronization。TransactionSynchronization接口定义了事务操作时的对应资源的(JDBC事务那么就是SqlSessionSynchronization)管理方法:

// 挂起事务 
void suspend();
// 唤醒事务
void resume();

void flush();
// 提交事务前
void beforeCommit(boolean readOnly);
 // 提交事务完成前
void beforeCompletion();
// 提交事务后
void afterCommit();
// 提交事务完成后
void afterCompletion(int status);

rollback回滚事务

在这里插入图片描述

AbstractPlatformTransactionManager中rollback源码:

	@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 {
				// 解绑当前线程绑定的会话工厂,并关闭会话
				triggerBeforeCompletion(status);

				if (status.hasSavepoint()) {// 1.如果有保存点,即嵌套式事务
					if (status.isDebug()) {
						logger.debug("Rolling back transaction to savepoint");
					}//回滚到保存点
					status.rollbackToHeldSavepoint();
				}
				//2.如果就是一个简单事务
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction rollback");
					}//回滚核心方法
					doRollback(status);
				}
				else {
					// Participating in larger transaction
					//3.当前存在事务且没有保存点,即加入当前事务的
					if (status.hasTransaction()) {
						//如果已经标记为回滚 或 当加入事务失败时全局回滚(默认true)
						if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
							}
							//设置当前connectionHolder:当加入一个已存在事务时回滚
							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) {
				//关闭会话,重置SqlSessionHolder属性
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				throw ex;
			}

			triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

			// Raise UnexpectedRollbackException if we had a global rollback-only marker
			if (unexpectedRollback) {
				throw new UnexpectedRollbackException(
						"Transaction rolled back because it has been marked as rollback-only");
			}
		}
		finally {
			// 解绑当前线程
			cleanupAfterCompletion(status);
		}
	}

Spring事务执行流程图:Spring事务的底层实现流程 | ProcessOn免费在线作图,在线流程图,在线思维导图 |

Spring事务传播机制

在开发过程中,经常会出现一个方法调用另外一个方法,那么这里就涉及到了多种场景,比如a()调用b():

  1. a()和b()方法中的所有sql需要在同一个事务中吗?
  2. a()和b()方法需要单独的事务吗?
  3. a()需要在事务中执行,b()还需要在事务中执行吗?
  4. 等等情况...

所以,这就要求Spring事务能支持上面各种场景,这就是Spring事务传播机制的由来。那Spring事务传播机制是如何实现的呢?

先来看上述几种场景中的一种情况,a()在一个事务中执行,调用b()方法时需要新开一个事务执行:

  1. 首先,代理对象执行a()方法前,先利用事务管理器新建一个数据库连接a
  2. 将数据库连接a的autocommit改为false
  3. 把数据库连接a设置到ThreadLocal中
  4. 执行a()方法中的sql
  5. 执行a()方法过程中,调用了b()方法(注意用代理对象调用b()方法)
    1. 代理对象执行b()方法前,判断出来了当前线程中已经存在一个数据库连接a了,表示当前线程其实已经拥有一个Spring事务了,则进行挂起
    2. 挂起就是把ThreadLocal中的数据库连接a从ThreadLocal中移除,并放入一个挂起资源对象
    3. 挂起完成后,再次利用事务管理器新建一个数据库连接b
    4. 将数据库连接b的autocommit改为false
    5. 把数据库连接b设置到ThreadLocal中
    6. 执行b()方法中的sql
    7. b()方法正常执行完,则从ThreadLocal中拿到数据库连接b进行提交
    8. 提交之后会恢复所挂起的数据库连接a,这里的恢复,其实只是把在挂起资源对象中所保存的数据库连接a再次设置到ThreadLocal中
  6. a()方法正常执行完,则从ThreadLocal中拿到数据库连接a进行提交

这个过程中最为核心的是:在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务了。

事务传播类型

事务传播机制只针对于同一线程,如果是多线程,则各使用各的事务。

 

案例分析

情况1

@Component
public class UserService {
 @Autowired
 private UserService userService;

 @Transactional
 public void test() {
  // test方法中的sql
		userService.a();
	}

 @Transactional
 public void a() {
  // a方法中的sql
	}
}

默认情况下传播机制为REQUIRED,表示当前如果没有事务则新建一个事务,如果有事务则在当前事务中执行。

所以上面这种情况的执行流程如下:

  1. 新建一个数据库连接conn
  2. 设置conn的autocommit为false
  3. 执行test方法中的sql
  4. 执行a方法中的sql
  5. 执行conn的commit()方法进行提交

情况2

假如是这种情况

@Component
public class UserService {
 @Autowired
 private UserService userService;

 @Transactional
 public void test() {
  // test方法中的sql
		userService.a();
        int result = 100/0;
	}

 @Transactional
 public void a() {
  // a方法中的sql
	}
}

所以上面这种情况的执行流程如下:

  1. 新建一个数据库连接conn
  2. 设置conn的autocommit为false
  3. 执行test方法中的sql
  4. 执行a方法中的sql
  5. 抛出异常
  6. 执行conn的rollback()方法进行回滚,所以两个方法中的sql都会回滚掉

情况3

假如是这种情况:

@Component
public class UserService {
 @Autowired
 private UserService userService;

 @Transactional
 public void test() {
  // test方法中的sql
		userService.a();
	}

 @Transactional
 public void a() {
  // a方法中的sql
        int result = 100/0;
	}
}

所以上面这种情况的执行流程如下:

  1. 新建一个数据库连接conn
  2. 设置conn的autocommit为false
  3. 执行test方法中的sql
  4. 执行a方法中的sql
  5. 抛出异常
  6. 执行conn的rollback()方法进行回滚,所以两个方法中的sql都会回滚掉

情况4

如果是这种情况:

@Component
public class UserService {
 @Autowired
 private UserService userService;

 @Transactional
 public void test() {
  // test方法中的sql
		userService.a();
	}

 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void a() {
  // a方法中的sql
  int result = 100/0;
	}
}

所以上面这种情况的执行流程如下:

  1. 新建一个数据库连接conn
  2. 设置conn的autocommit为false
  3. 执行test方法中的sql
  4. 又新建一个数据库连接conn2
  5. 执行a方法中的sql
  6. 抛出异常
  7. 执行conn2的rollback()方法进行回滚
  8. 继续抛异常,对于test()方法而言,它会接收到一个异常,然后抛出
  9. 执行conn的rollback()方法进行回滚,最终还是两个方法中的sql都回滚了

Spring事务强制回滚

正常情况下,a()调用b()方法时,如果b()方法抛了异常,但是在a()方法捕获了,那么a()的事务还是会正常提交的,但是有的时候,我们捕获异常可能仅仅只是不把异常信息返回给客户端,而是为了返回一些更友好的错误信息,而这个时候,我们还是希望事务能回滚的,那这个时候就得告诉Spring把当前事务回滚掉,做法就是:

@Transactional
public void test(){
 
    // 执行sql
 try {
		b();
	} catch (Exception e) {
  // 构造友好的错误信息返回
		TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
	}
    
}

public void b() throws Exception {
 throw new Exception();
}

TransactionSynchronization

Spring事务有可能会提交,回滚、挂起、恢复,所以Spring事务提供了一种机制,可以让程序员来监听当前Spring事务所处于的状态。

@Component
public class UserService {

 @Autowired
 private JdbcTemplate jdbcTemplate;

 @Autowired
 private UserService userService;

 @Transactional
 public void test(){
		TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

   @Override
   public void suspend() {
				System.out.println("test被挂起了");
			}

   @Override
   public void resume() {
				System.out.println("test被恢复了");
			}

   @Override
   public void beforeCommit(boolean readOnly) {
				System.out.println("test准备要提交了");
			}

   @Override
   public void beforeCompletion() {
				System.out.println("test准备要提交或回滚了");
			}

   @Override
   public void afterCommit() {
				System.out.println("test提交成功了");
			}

   @Override
   public void afterCompletion(int status) {
				System.out.println("test提交或回滚成功了");
			}
		});

		jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
		System.out.println("test");
		userService.a();
	}

 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void a(){
		TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

   @Override
   public void suspend() {
				System.out.println("a被挂起了");
			}

   @Override
   public void resume() {
				System.out.println("a被恢复了");
			}

   @Override
   public void beforeCommit(boolean readOnly) {
				System.out.println("a准备要提交了");
			}

   @Override
   public void beforeCompletion() {
				System.out.println("a准备要提交或回滚了");
			}

   @Override
   public void afterCommit() {
				System.out.println("a提交成功了");
			}

   @Override
   public void afterCompletion(int status) {
				System.out.println("a提交或回滚成功了");
			}
		});

		jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");
		System.out.println("a");
	}


}

Spring源码解析(四)--Spring事务的底层源码解析_李自富的博客-CSDN博客_spring事务源码深度解析

spring源码解析 (七) 事务底层源码实现_全场梦游c的博客-CSDN博客_spring 事务源码 

Tu--Ling 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值