Spring事务部分源码解析(三) - TransactionSynchronization

3,265 阅读4分钟

接下来阅读触发时间相关源码

AbstractPlatformTransactionManager

image-20190918180247521

可以看到触发事件有四个. commit前后,completion前后, 我们看下方代码比较直观

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

commit流程:

  1. 预提交(扩展)
  2. 触发triggerBeforeCommit
  3. 触发triggerBeforeCompletion
  4. 提交
  5. 发生TransactionException异常说明已经被标记rollback或者需要rollback,则执行triggerAfterCompletion处理,最终执行cleanupAfterCompletion
  6. 发生RuntimeException或者Error则会判断是否执行triggerBeforeCompletion,如果执行则执行triggerAfterCompletion,如果未执行则先triggerBeforeCompletion,最终执行cleanupAfterCompletion
  7. triggerAfterCommit
  8. triggerAfterCompletion
  9. cleanupAfterCompletion
private void processRollback(DefaultTransactionStatus status) {
	try {
		try {
			triggerBeforeCompletion(status);
			if (status.hasSavepoint()) {
				if (status.isDebug()) {
					logger.debug("Rolling back transaction to savepoint");
				}
				status.rollbackToHeldSavepoint();
			}
			else if (status.isNewTransaction()) {
				if (status.isDebug()) {
					logger.debug("Initiating transaction rollback");
				}
				doRollback(status);
			}
			else 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");
			}
		}
		catch (RuntimeException ex) {
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
			throw ex;
		}
		catch (Error err) {
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
			throw err;
		}
		triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
	}
	finally {
		cleanupAfterCompletion(status);
	}
}

Rollback流程:

  1. 触发triggerBeforeCompletion
  2. rollback(并不一定触发回滚,可能是设置回滚标识)
  3. 发生异常触发triggerAfterCompletion,并往上抛
  4. 触发triggerAfterCompletion
  5. cleanupAfterCompletion

triggerBeforeCommit

image-20190918181806849

image-20190918185623952

image-20190918185926385

triggerAfterCommit

image-20190918181905137

image-20190918185648103

image-20190918185953086

image-20190918190011335

triggerBeforeCompletion

image-20190918182207864

image-20190918185712074

image-20190918190053220

triggerAfterCompletion

image-20190918182444899

image-20190918185733079

image-20190918190737482

到这里,我们的关注点就应该是TransactionSynchronization.至于TransactionSynchronizationUtils,只是通过TransactionSynchronizationManager..getSynchronizations()获取TransactionSynchronization,然后遍历调用而已

TransactionSynchronization

image-20190918191254211

子类

image-20190918191314396

SqlSessionSynchronization(Mybatis)

image-20190918221701492

RabbitResourceSynchronization

image-20190918191514543

RedisTransactionSynchronizer

image-20190918215145038

仅举例表示对接实现

目前项目中使用RabbitMQ, 当RabbitTemplate.channelTransacted = true时,会绑定TransactionSynchronization在使用@Transactional的方法之后会走到此处,执行RabbitMQ的发送和回滚

我们发现两个类是继承了ResourceHolderSynchronization

ResourceHolderSynchronization

image-20190918220026988

相比TransactionSynchronization 增加了红框的几个方法

核心的commit和completion已经做出抽象实现.具体又子类具体实现

看一下代码

@Override
	public void suspend() {
		if (this.holderActive) {
			TransactionSynchronizationManager.unbindResource(this.resourceKey);
		}
	}

	@Override
	public void resume() {
		if (this.holderActive) {
			TransactionSynchronizationManager.bindResource(this.resourceKey, this.resourceHolder);
		}
	}

	@Override
	public void flush() {
		flushResource(this.resourceHolder);
	}

	@Override
	public void beforeCommit(boolean readOnly) {
	}

	@Override
	public void beforeCompletion() {
		if (shouldUnbindAtCompletion()) {
			TransactionSynchronizationManager.unbindResource(this.resourceKey);
			this.holderActive = false;
			if (shouldReleaseBeforeCompletion()) {
				releaseResource(this.resourceHolder, this.resourceKey);
			}
		}
	}

	@Override
	public void afterCommit() {
		if (!shouldReleaseBeforeCompletion()) {
			processResourceAfterCommit(this.resourceHolder);
		}
	}

	@Override
	public void afterCompletion(int status) {
		if (shouldUnbindAtCompletion()) {
			boolean releaseNecessary = false;
			if (this.holderActive) {
				// The thread-bound resource holder might not be available anymore,
				// since afterCompletion might get called from a different thread.
				this.holderActive = false;
				TransactionSynchronizationManager.unbindResourceIfPossible(this.resourceKey);
				this.resourceHolder.unbound();
				releaseNecessary = true;
			}
			else {
				releaseNecessary = shouldReleaseAfterCompletion(this.resourceHolder);
			}
			if (releaseNecessary) {
				releaseResource(this.resourceHolder, this.resourceKey);
			}
		}
		else {
			// Probably a pre-bound resource...
			cleanupResource(this.resourceHolder, this.resourceKey, (status == STATUS_COMMITTED));
		}
		this.resourceHolder.reset();
	}


	/**
	 * Return whether this holder should be unbound at completion
	 * (or should rather be left bound to the thread after the transaction).
	 * <p>The default implementation returns {@code true}.
	 */
	protected boolean shouldUnbindAtCompletion() {
		return true;
	}

	/**
	 * Return whether this holder's resource should be released before
	 * transaction completion ({@code true}) or rather after
	 * transaction completion ({@code false}).
	 * <p>Note that resources will only be released when they are
	 * unbound from the thread ({@link #shouldUnbindAtCompletion()}).
	 * <p>The default implementation returns {@code true}.
	 * @see #releaseResource
	 */
	protected boolean shouldReleaseBeforeCompletion() {
		return true;
	}

	/**
	 * Return whether this holder's resource should be released after
	 * transaction completion ({@code true}).
	 * <p>The default implementation returns {@code !shouldReleaseBeforeCompletion()},
	 * releasing after completion if no attempt was made before completion.
	 * @see #releaseResource
	 */
	protected boolean shouldReleaseAfterCompletion(H resourceHolder) {
		return !shouldReleaseBeforeCompletion();
	}

	/**
	 * Flush callback for the given resource holder.
	 * @param resourceHolder the resource holder to flush
	 */
	protected void flushResource(H resourceHolder) {
	}

	/**
	 * After-commit callback for the given resource holder.
	 * Only called when the resource hasn't been released yet
	 * ({@link #shouldReleaseBeforeCompletion()}).
	 * @param resourceHolder the resource holder to process
	 */
	protected void processResourceAfterCommit(H resourceHolder) {
	}

	/**
	 * Release the given resource (after it has been unbound from the thread).
	 * @param resourceHolder the resource holder to process
	 * @param resourceKey the key that the ResourceHolder was bound for
	 */
	protected void releaseResource(H resourceHolder, K resourceKey) {
	}

	/**
	 * Perform a cleanup on the given resource (which is left bound to the thread).
	 * @param resourceHolder the resource holder to process
	 * @param resourceKey the key that the ResourceHolder was bound for
	 * @param committed whether the transaction has committed ({@code true})
	 * or rolled back ({@code false})
	 */
	protected void cleanupResource(H resourceHolder, K resourceKey, boolean committed) {
	}

可能这里讲的比较乱.大概说一下这些用途吧 TransactionSynchronization这个类更多扩展的用途是在于afterCompletion,对于像jdbc,rabbit,redis这些可以在执行结束后释放Transactional resources

我们再回头想一下,我们是从TransactionSynchronizationManager才找到TransactionSynchronization.为什么TransactionSynchronization会放在TransactionSynchronizationManager.TransactionSynchronizationManager的意义在于什么?我们看一下

TransactionSynchronizationManager

image-20190918221920971

方法大致如下 注册,解绑,绑定,获取,清空 我们看一下属性

image-20190918222051306

看到ThreadLocal,似乎知道了些什么 多个线程,每个线程又需要对应多个厂商的事务连接,并且每个事务连接朝生夕死,虽然spring容器支持多例,但是多例如何传递?需要怎么处理? 通过TransactionSynchronizationManager的ThreadLocal来在线程上下文传递.也许才是最解耦最优雅的方式

总结

AbstractPlatformTransactionManager提供抽象方法,子类具体实现(RabbitTransactionManager, DataSourceTransactionManager) TransactionSynchronization提供接口供第三方扩展注册,用于一个事务的多方处理(db, mq等, 实现如RabbitResourceSynchronization, RedisTransactionSynchronizer, SqlSessionSynchronization) 那么问题又来了AbstractPlatformTransactionManager的实现类在什么时候注册,是么时候获取? TransactionSynchronization的实现类在什么时候注册?什么时候绑定?什么时候获取? 写一篇讲解Spring定义抽象的实现类何时加载处理