提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
本文主要从源码角度分析事务的传播机制的实现原理,理解有限,欢迎交流。
一、传播事务建立过程
首先分析一下事务传播机制的建立的大致流程,主要是在有外层事务的情况下,对外层事务是否挂起,是否创建并开启新的事务,其中的suspend方法比较重要,是将外层事务的一些属性记录下来并返回,最终写入到新的事务中,方便在内层事务运行结束后再次执行外层事务。
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// PROPAGATION_NOT_SUPPORTED:将原先事务挂起,不开启新事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// PROPAGATION_REQUIRES_NEW:将原先事务挂起,并开启新事务运行
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
启新事务,继续使用原先事务 ,加入当前事务,隔离级别和只读属性不一致时报异常
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//创建一个不同的TransactionStatus对象,将newTransaction属性设置为false,发生异常不会直接回滚,而是会doSetRollbackOnly,在外层事务中回滚
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
二、事务唤醒步骤
事务唤醒的主要过程就是恢复外层事务在本地线程中的值,主要涉及cleanupAfterCompletion和cleanupTransactionInfo两个方法,下面进行源码分析。
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
doCleanupAfterCompletion(status.getTransaction());
}
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
//唤醒挂起事务
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
protected void doResume(Object transaction, Object suspendedResources) {
// 将挂起的资源重新绑定到本地线程中
TransactionSynchronizationManager.bindResource(this.dataSource, suspendedResources);
}
protected void cleanupTransactionInfo(TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
} private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
}
总结
整体来看事务的传播机制还是比较容易理解的,在需要使用新事务的时候判断当前是否存在事务,如果存在,根据不同的事务传播机制,选择性的将原先事务挂起,或者加入原先事务,还是新建事务执行,同时在新事务的相关对象中记录原先事务的相关属性,在新事务执行完成后恢复原先事务的状态,将相关数据写入本地线程中,继续以原先事务执行。