Spring事务执行过程-TransactionInterceptor-源码解析

背景

因为Spring声明式事务是通过AOP增强实现的,所以现在具体来分析一下Spring事务的执行过程,因为AOP是通过拦截器执行链实现的,所以我们可以把关注点聚焦在拦截器上-TransactionInterceptor

事例

    @Transactional
    public void insertUser(String name,int age){
        userMapper.insertUser(name,age);
    }
    @Test
    public void insertUser(){
        userService.insertUser("test",123);
    }

执行测试用例并DEBUG

  • 从图中可以看到UserService中的insertUser加了事务注解,所以被AOP代理了
  • 并且可以看到只包含一个增强器,增强器使用的增强通知是-TransactionInterceptor
  • 断点往下执行,就是执行AOP拦截器执行链的过程,这里就不再展开的,需要了解AOP执行过程的可以看我之前的文章Spring AOP初始化及执行过程
  • 那么我们下面直接围绕TransactionInterceptor展开说明
    在这里插入图片描述

Spring事务处理逻辑的核心-TransactionInterceptor

类图
  • 本身属于AOP中的Advice通知
  • 为了集成到Spring AOP的拦截器执行链,继承了MethodInterceptor
    在这里插入图片描述
TransactionInterceptor invoke()
  • 拦截器接口的方法,拦截器被执行器调用的方法
    /**
	 * @param invocation 拦截器链的执行器,用于执行下一个拦截器
	 * @return 返回连接点的执行结果
	 * @throws Throwable
	 */
	@Override
	@Nullable
	public Object invoke(MethodInvocation invocation) throws Throwable {
		//获取被代理对象的类类型
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		//调用父类TransactionAspectSupport方法
		//传入连接点方法对象,代理对象类类型,拦截器执行器MethodInvocation的proceed()方法引用
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}
TransactionInterceptor invokeWithinTransaction()
  • 执行事务的逻辑
   /** 执行事务逻辑
	 * @param method 连接点的方法对象
	 * @param targetClass 被代理的对象,用于执行method
	 * @param invocation 用于执行下一个拦截器
	 * @return the return value of the method, if any
	 * @throws Throwable propagated from the target invocation
	 */
	@Nullable
	protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {


		//事务注解属性源,包含了保存 事务注解属性的缓存 如果为空不执行事务
		TransactionAttributeSource tas = getTransactionAttributeSource();
		//事务注解属性对象
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		//事务管理器
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		//获取连接点唯一标识字符串  com.example.UserService.insertUser()
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
		//如果是本地事务执行逻辑
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {

			//创建事务并返回事务对象信息
			//TransactionInfo 事务信息对象  主要包含 TransactionStatus TransactionAttribute PlatformTransactionManager
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			try {
				//执行下一个拦截器,如果只有一个拦截器,那么下一个会执行连接点的方法()
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				//事务回滚
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				//清除事务信息
				cleanupTransactionInfo(txInfo);
			}
			//提交事务
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
	......

创建事务

createTransactionIfNecessary
  • 如果需要则创建事务,需要根据事务传播级别来判断是否创建事务
/**
	 * 如果需要则创建事务,需要根据事务传播级别来判断是否创建事务
	 * @param txAttr the TransactionAttribute (may be {@code null})
	 * @param joinpointIdentification 连接点执行方法的唯一标识
	 * @return a TransactionInfo object, whether or not a transaction was created.
	 * The {@code hasTransaction()} method on TransactionInfo can be used to
	 * tell if there was a transaction created.
	 * @see #getTransactionAttributeSource()
	 */
	@SuppressWarnings("serial")
	protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

        //如果没有执行名称,则使用joinpointIdentification,并返回代理对象
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}

		TransactionStatus status = null;
		//事务属性不为null
		if (txAttr != null) {
			//事务管理器不为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");
				}
			}
		}
		//创建并初始化TransactionInfo
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}
	
getTransaction 获取事务
/**
	 * This implementation handles propagation behavior. Delegates to
	 * {@code doGetTransaction}, {@code isExistingTransaction}
	 * and {@code doBegin}.
	 * @see #doGetTransaction
	 * @see #isExistingTransaction
	 * @see #doBegin
	 */
	@Override
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
		//返回DataSourceTransactionObject 持有ConnectionHolder 数据库连接
		//如果当前线程已经存在事务,则会从ThreadLocal的Map 以DataSource为key获取ConnectionHolder
		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)) {
			//根据事务隔离传播处理事务
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		//注意:以下处理逻辑为不存在事务
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		//事务传播级别为PROPAGATION_MANDATORY,不存在事务抛出异常
		if (definition.getPropagationBehavior() == TransactionDefinition.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) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				//创建status
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				//开启事务 获取连接 设置数据库事务隔离级别 设置超时时间 绑定连接资源到本地线程
				doBegin(transaction, definition);
				//初始化事务同步器TransactionSynchronizationManager
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		//如果不是以上四种支持事务的传播级别,
		//即为PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER
		//这三种传播级别以非事务的方式执行
		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);
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}
deBegin 创建新的事务
/**
	 * This implementation sets the isolation level but ignores the timeout.
	 */
	@Override
	protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				//从数据源获取新的连接
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();

			//设置 数据库事务隔离界别
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			txObject.setPreviousIsolationLevel(previousIsolationLevel);

			// 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).
			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);
			}

			// 绑定新的连接到本地线程 key为对应的数据源
			if (txObject.isNewConnectionHolder()) {
				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);
		}
	}

回滚

回滚的情况
  • 事务执行过程中,抛出异常,默认回滚RuntimeException和Error
  • 通过手动回滚,在业务方法中执行以下操作,会在提交方法中判断是否回滚
    • TransactionInterceptor.currentTransactionStatus().setRollbackOnly()
当连接点方法执行发生异常,会被catch捕获到,执行回滚逻辑
......
try {
				//执行下一个拦截器,如果只有一个拦截器,那么下一个会执行连接点的方法()
				retVal = invocation.proceedWithInvocation();
			}
			//捕获连接点抛出的异常
			catch (Throwable ex) {
				//事务回滚
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
 ........
completeTransactionAfterThrowing
  • 匹配异常,进行回滚
    • 当在@Transactional中没有定义rollbackFor,默认只回滚RuntimeException和Error
    • 调用数据库连接对象Connection的rollback()进行回滚
  • 如果没有匹配的异常,会执行commit()
    • 在commit()方法中,会进行手动回滚的判断
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);
			}
			//使用RuleBasedTransactionAttribute判断当前异常是否需要回滚-如果注解上定义了@Transactional(rollbackFor = Exception.class)
			//这里会使用ex向上递归查找父类是否和Exception是否相同,如果相同则进行回滚
			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 {
				//commit() 会判断通过手动设置回滚的操作,然后也会进行回滚
				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;
				}
			}
		}
	}
txInfo.getTransactionManager().commit()中进行手动回滚判断
  • 可以在连接点方法中执行TransactionInterceptor.currentTransactionStatus().setRollbackOnly(),这里会进行判断并且执行回滚操作
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;
		//如果执行了TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
		//这里会判断为true并且进行回滚操作
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}

		//通过ConnectHolder setRollbackOnly() 设置的回滚
		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);
	}
手动回滚事例
    @Transactional
    public void insertUser(String name,int age) throws Exception {
        userMapper.insertUser(name,age);
        //手动回滚
        TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
    }
   @Test
    public void insertUser() throws Exception {
        userService.insertUser("test",123);
        //查询结果
        userService.selectUser();
    }
执行结果
  • test并没有插入成功,并且从控制台中也打印了进行回滚的日志
[{ID=1, NAME=小明, AGE=23}, {ID=2, NAME=小白, AGE=24}]
22:58:09.131 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Transactional code has requested rollback

以上回滚日志对应到

if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}

提交

  • 连接点方法执行完成,并且没有捕获异常,最后执行提交事务方法commitTransactionAfterReturning
  • 最后也是调用jdbc中Connection的commit()进行提交操作
   .........
         try {
		   //执行下一个拦截器,如果只有一个拦截器,那么下一个会执行连接点的方法()
				retVal = invocation.proceedWithInvocation();
			 }
			//捕获连接点抛出的异常
			catch (Throwable ex) {
				//事务回滚
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				//清除事务信息
				cleanupTransactionInfo(txInfo);
			}
			//提交事务
			commitTransactionAfterReturning(txInfo);
			return retVal;
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
		}
	
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;
		//如果执行了TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
		//这里会判断为true并且进行回滚操作
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}

		//通过ConnectHolder setRollbackOnly() 设置的回滚
		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);
	}

总结

  • 创建事务时会根据事务传播级别进行处理
    • 当前线程不同数据库操作引用同一个事务会使用同一个JDBC Connection,否则会建立新的事务或新的连接
  • 事务回滚
    • 抛出异常
    • 手动回滚
  • 如果连接点执行完毕,则进行提交
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值