【Spring事务详解】--- 8.beforeCommit、beforeCompletion、afterCommit、afterCompletion实现分析

前言

beforeCommit、beforeCompletion、afterCommit、afterCompletion是Spring为我们在事务提交前、后提供的扩展点,业务在实际使用时可以通过这几个方法在事务提交前、后实现一些额外的逻辑控制,尤其是有些需要在事务提交后才能处理的逻辑,利用afterCommit或者afterCompletion可以非常方便的实现,本文就来简单分析一下Spring是通过什么样的方式来预埋这几个方法的。

Spring事务详解连载

【Spring事务详解】— 1.事务传播的案例演示
【Spring事务详解】— 2.事务应用的注意事项
【Spring事务详解】— 3.事务失效的八种场景
【Spring事务详解】— 4.事务管理器的架构分析
【Spring事务详解】— 5.事务管理器TransactionSynchronizationManager分析
【Spring事务详解】— 6.事务创建的流程分析
【Spring事务详解】— 7.事务提交、回滚的流程分析
【Spring事务详解】— 8.beforeCommit、beforeCompletion、afterCommit、afterCompletion实现分析

TransactionSynchronization

首先这几个方法是定义在TransactionSynchronization接口中的,并且定义的都是default方法,默认没有任何处理。

public interface TransactionSynchronization extends Ordered, Flushable {
	default void beforeCommit(boolean readOnly) {
	}
	
	default void beforeCompletion() {
	}
	
	default void afterCommit() {
	}
	
	default void afterCompletion(int status) {
	}
}

afterCommit方法分析

afterCommit方法为例,我们来简单分析一下实现逻辑,其他的3个实现方法大体一致。

1.找到方法调用的入口

TransactionTemplate

如果你使用的是编程式事务,那么TransactionTemplate类的execute方法则是整个事务执行的入口,由于我们只分析afterCommit的实现逻辑,所以我们直接看相关方法即可,在exceute中,就是transactionManager.commit方法。

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
	Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
	if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
		return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
	}
	else {
		TransactionStatus status = this.transactionManager.getTransaction(this);
		T result;
		try {
			result = action.doInTransaction(status);
		}
		catch (RuntimeException | Error ex) {
			// Transactional code threw application exception -> rollback
			rollbackOnException(status, ex);
			throw ex;
		}
		catch (Throwable ex) {
			// Transactional code threw unexpected exception -> rollback
			rollbackOnException(status, ex);
			throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
		}
		// 当前面事务处理完成之后,直接调用事务提交的方法。
		this.transactionManager.commit(status);
		return result;
	}
}

AbstractPlatformTransactionManager

如果是使用声明式事务,那么入口就是commit方法。

事务提交的方法由AbstractPlatformTransactionManager控制,逻辑也很明显,processCommit是真正的执行方法。

@Override
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;
	if (defStatus.isLocalRollbackOnly()) {
		if (defStatus.isDebug()) {
			logger.debug("Transactional code has requested rollback");
		}
		processRollback(defStatus, false);
		return;
	}
	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);
}

// processCommit方法定义了流程处理的主体结构,然后通过doCommit方法,让具体的事务管理器去实现。
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
	try {
		boolean beforeCompletionInvoked = false;
		try {
			boolean unexpectedRollback = false;
			prepareForCommit(status);
			// 这两步就对应这beforeCommit、beforeCompletion的逻辑
			triggerBeforeCommit(status);
			triggerBeforeCompletion(status);
			beforeCompletionInvoked = true;
			if (status.hasSavepoint()) {
				if (status.isDebug()) {
					logger.debug("Releasing transaction savepoint");
				}
				unexpectedRollback = status.isGlobalRollbackOnly();
				status.releaseHeldSavepoint();
			}
			else if (status.isNewTransaction()) {
				if (status.isDebug()) {
					logger.debug("Initiating transaction commit");
				}
				unexpectedRollback = status.isGlobalRollbackOnly();
				// 真正执行事务提交的方法,交给了具体的事务处理器去执行
				doCommit(status);
			}
			else if (isFailEarlyOnGlobalRollbackOnly()) {
				unexpectedRollback = status.isGlobalRollbackOnly();
			}
			// Throw UnexpectedRollbackException if we have a global rollback-only
			// marker but still didn't get a corresponding exception from commit.
			if (unexpectedRollback) {
				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 | Error ex) {
			if (!beforeCompletionInvoked) {
				triggerBeforeCompletion(status);
			}
			doRollbackOnCommitException(status, ex);
			throw ex;
		}
		// Trigger afterCommit callbacks, with an exception thrown there
		// propagated to callers but the transaction still considered as committed.
		try {
			// 当事务提交成功之后,调用triggerAfterCommit方法,afterCommit逻辑入口也在这
			triggerAfterCommit(status);
		}
		finally {
			// afterCompletion的入口。
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
		}
	}
	finally {
		cleanupAfterCompletion(status);
	}
}


// 调用TransactionSynchronizationUtils类的triggerAfterCommit方法
private void triggerAfterCommit(DefaultTransactionStatus status) {
	if (status.isNewSynchronization()) {
		TransactionSynchronizationUtils.triggerAfterCommit();
	}
}

TransactionSynchronizationUtils

到了TransactionSynchronizationUtils之后,处理流程就很简单了,获取TransactionSynchronization集合,挨个遍历调用即可。

public static void triggerAfterCommit() {
	invokeAfterCommit(TransactionSynchronizationManager.getSynchronizations());
}

public static void invokeAfterCommit(@Nullable List<TransactionSynchronization> synchronizations) {
	if (synchronizations != null) {
		for (TransactionSynchronization synchronization : synchronizations) {
			// 最终调用到afterCommit方法
			synchronization.afterCommit();
		}
	}
}	

通过以上的流程分析可以看出,Spring就是简单的把执行afterCommit方法放在事务提交后调用。

2.获取TransactionSynchronization集合

根据前面的流程分析可能,synchronizations集合是通过调用TransactionSynchronizationManager.getSynchronizations()方法获取的。

public static void triggerAfterCommit() {
	invokeAfterCommit(TransactionSynchronizationManager.getSynchronizations());
}

getSynchronizations

private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
		new NamedThreadLocal<>("Transaction synchronizations");

public static List<TransactionSynchronization> getSynchronizations() throws IllegalStateException {
	// synchronizations是TransactionSynchronizationManager类中定义的一个ThreadLocal全局变量
	Set<TransactionSynchronization> synchs = synchronizations.get();
	// 如果为null,则抛出异常
	if (synchs == null) {
		throw new IllegalStateException("Transaction synchronization is not active");
	}
	// Return unmodifiable snapshot, to avoid ConcurrentModificationExceptions
	// while iterating and invoking synchronization callbacks that in turn
	// might register further synchronizations.
	// 为空,直接返回
	if (synchs.isEmpty()) {
		return Collections.emptyList();
	}
	else {
		// Sort lazily here, not in registerSynchronization.
		// 排序后,返回集合快照
		List<TransactionSynchronization> sortedSynchs = new ArrayList<>(synchs);
		OrderComparator.sort(sortedSynchs);
		return Collections.unmodifiableList(sortedSynchs);
	}
}

3.synchronizations添加元素

很明显,现在问题又变成了synchronizations这个ThreadLocal全局变量是何时被赋值的?

首先在事务开始前,就会通过调用initSynchronization方法,先对其进行初始化,这个方法入口也很容易找到,就在TransactionTemplateexecute方法中,通过调用this.transactionManager.getTransaction(this)方法,完成初始化。

public static void initSynchronization() throws IllegalStateException {
	if (isSynchronizationActive()) {
		throw new IllegalStateException("Cannot activate transaction synchronization - already active");
	}
	synchronizations.set(new LinkedHashSet<>());
}

TransactionSynchronizationManager还提供了registerSynchronization方法可以对其进行添加元素。

public static void registerSynchronization(TransactionSynchronization synchronization)
		throws IllegalStateException {
	Assert.notNull(synchronization, "TransactionSynchronization must not be null");
	Set<TransactionSynchronization> synchs = synchronizations.get();
	if (synchs == null) {
		throw new IllegalStateException("Transaction synchronization is not active");
	}
	synchs.add(synchronization);
}

4.实际使用方式

所以,一般我们自定义的方法都是这样实现的,通过匿名类的方式,直接添加一个TransactionSynchronization类型的元素到synchronizations集合中

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
    @Override
    public void afterCompletion(int status) {
        // 实现你的业务逻辑,在前面分析的invokeAfterCommit方法中,会调用到这里
    }
});
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
@Transactional(rollbackFor = Exception.class) public void IntendedSignHandle(IntendedSignReq intendedSignReq, Map<String, IntentionEquResp> intentionEquRespMap, SaleStateEnum currentSaleStateEnum, SaleStateEnum goalSaleStateEnum) { StringBuilder message = new StringBuilder(); List<EquMarketablePrice> updateMarketablePriceList = new ArrayList<>(); for (String equNo : intendedSignReq.getEquNoList()) { Optional.ofNullable(intentionEquRespMap.get(equNo)).ifPresent(intentionEquResp -> { // 构建更新对象 if (intentionEquResp.getSaleState().equals(currentSaleStateEnum.getCode())) { EquMarketablePrice updateEquMarketablePrice = new EquMarketablePrice(); updateEquMarketablePrice.setId(intentionEquResp.getId()); updateEquMarketablePrice.setSaleState(goalSaleStateEnum.getCode()); updateEquMarketablePrice.setEditBy(intendedSignReq.getOperatorAd()); updateEquMarketablePrice.setEditByName(intendedSignReq.getOperatorName()); updateMarketablePriceList.add(updateEquMarketablePrice); } else { message.append(String.format("[%s] 当前意向状态[%s] 非[%s]状态,无法标记[%s]状态,请与资产方向确认", equNo, SaleStateEnum.getDescByCode(intentionEquResp.getSaleState()), currentSaleStateEnum.getDesc(), goalSaleStateEnum.getDesc())).append("\n"); } }); } if (CollectionUtils.isNotEmpty(updateMarketablePriceList)) { equMarketablePriceService.updateBatchById(updateMarketablePriceList, Constant.ONE_HUNDRED); } TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { if (StringUtils.isBlank(message) ) { return; } String errorMessage = message.toString(); log.info(errorMessage); if (Boolean.TRUE.equals(intendedSignSwitch)) { alarmService.alarm("意向标记失败", errorMessage); } } }); } 允许报这个错java.lang.IllegalStateException: Transaction synchronization is not active
最新发布
07-15

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值