Spring事务部分源码解析(二) - 事务管理器

685 阅读4分钟

按照上篇流程详解

获取方法的Transaction配置

按照上篇对于几个实体类的描述,可以发现注解@Transactional的属性的字段和TransactionDefinition大致比较相似,但又不完全一致.

从@Transactional开始讲起

这个显然很常见,就是我们平时需要事务时用到的注解.可是spring如何去解析?我们看一下使用到这个注解的地方,排除掉在test和comment下的使用.

进入方法

TransactionAttribute正是上篇文章中TransactionDefinition的子类

返回的RuleBasedTransactionAttribute我们看一下他的继承图

我们打开源码看一下RuleBasedTransactionAttribute和父类DefaultTransactionAttribute晚上寻找发现,事务常规的设置是继承DefaultTransactionDefinition来注入,rollback相关则实现TransactionAttribute.这就是我们上篇提到TransactionAttribute和TransactionDefinition责任的划分

我们网上追溯,调用方

AnnotationTransactionAttributeSource.findTransactionAttribute()

AbstractFallbackTransactionAttributeSource.computeTransactionAttribute

AnnotationTransactionAttributeSource.getTransactionAttribute()

TransactionAspectSupport.invokeWithinTransaction

获取Transaction配置流程:根据方法和类确定唯一key,从缓存中获取.如果获取不到则通过TransactionAnnotationParser解析方法来获取事务属性.并放置缓存中

获取事务管理器(PlatformTransactionManager)

接口定义方法(可以发现极其精简干净)

抽象子类AbstractPlatformTransactionManager, 可以发现多了很多方法.但并没有实现,用于子类继承处理

子类

我们可以关注一下DataSourceTransactionManager和RabbitTransactionManager,是抽象类的一个实现.DataSourceTransactionManager的具体实现是通过Java提供的接口实现.而RabbitTransactionManager则是自己实现(毕竟已经属于定制了)

此处可以回顾TransactionAspectSupport.invokeWithinTransaction(), 开启事务后上下文通过TransactionInfo传递信息. 每当设计事务提交或回滚等相关,都是txInfo.getTransactionManager().commit()/rollback()

AbstractPlatformTransactionManager.rollback()

大致说一下回滚流程.

  1. 触发TransactionSynchronization完成前事件
  2. 事务具体实现的真正回滚
  3. 触发TransactionSynchronization完成后事件
  4. 标记完成,执行后续清理操作
ps: 如果一个方法需要执行多个事务如何处理?(剧透一下:TransactionSynchronization)

AbstractPlatformTransactionManager.commit()

从图中看出在某种情况会执行回滚操作.最开始看到这里的时候也迷过.后来在一次事务测试时,同一个事务,方法嵌套时,内部方法抛异常,但是外部方法捕获正常处理.一部分觉得内部回滚外部不回滚.实际结果是内外都会回滚和是否捕获并没有关系. 可以回顾一下processRollback()中的status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()判断

private boolean globalRollbackOnParticipationFailure = true;

默认为true,也就是说在非特意设置的情况下会执行doSetRollbackOnly(status);将rollbackOnly设置为true.在也就是说当内部内部方法发生异常之后会上下文TransactionStatus.rollbackOnly为true,执行的便是processRollback().这也就解释为什么内部方法捕获之后依旧会回滚的原因/

ps: 本身在同一个事务,内部方法发生异常执行回滚,理应是整个事务回滚而不是部分回滚.以为捕获异常处理之后再提交这种思想本身就不对噢!!!

如果没有发生异常.则执行正常提交流程

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;
			try {
				prepareForCommit(status);
				triggerBeforeCommit(status);
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;
				boolean globalRollbackOnly = false;
				if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
					globalRollbackOnly = status.isGlobalRollbackOnly();
				}
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					status.releaseHeldSavepoint();
				}
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction commit");
					}
					doCommit(status);
				}
				// Throw UnexpectedRollbackException if we have a global rollback-only
				// marker but still didn't get a corresponding exception from commit.
				if (globalRollbackOnly) {
					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 ex) {
				if (!beforeCompletionInvoked) {
					triggerBeforeCompletion(status);
				}
				doRollbackOnCommitException(status, ex);
				throw ex;
			}
			catch (Error err) {
				if (!beforeCompletionInvoked) {
					triggerBeforeCompletion(status);
				}
				doRollbackOnCommitException(status, err);
				throw err;
			}

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

		}
		finally {
			cleanupAfterCompletion(status);
		}
	}

执行流程

  1. 执行预提交处理
  2. 触发提交前事件
  3. 触发完成事件
  4. 提交
  5. 触发提交事件
  6. 触发提交完成事件
  7. 清除状态
个人理解的第一步是预留分布式事务接口. 而后续的触发时间则是扩展处理(后续讲TransactionSynchronization会聊到),不过这个扩展处理划分的也太细了

AbstractPlatformTransactionManager.cleanupAfterCompletion()

其实这里也没什聊的,打开方法的源码基本能发现都是清除上下文状态.也代表事务的结束

总结

  1. AbstractPlatformTransactionManager实现了核心的逻辑,每一个核心的逻辑的具体实现又留给各个厂商实现.这一部分挺像AbstractQueuedSynchronizer的.设计挺好的.扩展性好,具体的逻辑又帮你实现好.只需要继承定制实现自己非常简单的逻辑就好
  2. 事务嵌套情况通过线程上线文来处理
  3. 多事务通过触发事件处理(后续讲TransactionSynchronization会聊到),扩展性真的挺好
下一篇讲触发事件处理.相关类TransactionSynchronizationManager, TransactionSynchronizationUtils, TransactionSynchronization