Spring事务系列
2、【源码】Spring Data JPA原理解析之事务注册原理
3、【源码】Spring Data JPA原理解析之事务执行原理
5、【源码】Spring事务之传播特性的详解
前言
《Spring事务系列》的前面4篇博文从源码的角度分析了Spring事务的注册以及执行原理,本篇分享一下事务的传播特性。
事务传播特性
Spring事务包含七种的传播特性,在Propagation枚举类中,分别如下:
1)REQUIRE:如果当前没有事务,则新创建一个事务;如果上下文存在事务,则加入到这个事务中。默认值;
2)SUPPORTS:如果当前上下文存在事务,则加入这个事务;如果上下文不存在事务,则使用无事务的方式执行。即:如果上下文有事务,则加入这个事务;否则直接执行,不会新创建事务;
3)MANDATORY:如果当前上下文存在事务,则加入这个事务;如果上下文不存在事务,则报错;
4)REQUIRES_NEW:每次都新创建一个事务。如果当前上下文有事务,则挂起上下文的事务,重新创建一个事务;如果当前上下文没有事务,新创建一个事务;
如:ServiceA.method()调用ServiceB.method(),在ServiceB.method()使用REQUIRES_NEW传播特性。如果ServiceB.method()提交后,ServiceA.method()报错,则ServiceB.method()不会回滚,ServiceA.method()会回滚;如果ServiceB.method()报错,则ServiceA.method()可以通过捕获异常,选择回滚或提交。
5)NOT_SUPPORTED:不支持事务执行。如果当前上下文存在事务,则挂起上下文事务;
如:ServiceA.method()调用ServiceB.method(),在ServiceB.method()使用NOT_SUPPORTED传播特性,则ServiceB.method()的执行不在事务范围内。如果ServiceB.method()报错,则ServiceA.method()可以通过捕获异常,选择回滚或提交。
6)NEVER:无事务执行。如果当前上下文存在事务,则抛异常;
如:ServiceA.method()调用ServiceB.method(),在ServiceB.method()使用NEVER传播特性,则ServiceB.method()的整条调用链中都不能创建事务,否则会报错。
7)NESTED:嵌套事务。如果上下文存在事务,则在嵌套的事务中执行;如果上下文没有事务,则新创建一个事务;
如:ServiceA.method()调用ServiceB.method(),在ServiceB.method()使用NESTED传播特性。如果ServiceB.method()报错,则只回滚ServiceB.method()中的信息,对ServiceA.method()没有影响。通过savepoint实现。
源码解析
事务的传播特性可以通过@Transactional注解的propagation属性进行设置,对于Propagation枚举类中每一种传播特性,在TransactionDefinition中都对应一个属性值。
3.1 Propagation
Propagation的源码如下:
public enum Propagation {
// 需要事务。如果当前没有事务,则新创建一个事务;如果上下文存在事务,则加入到这个事务中。默认值;
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
// 如果当前上下文存在事务,则加入这个事务;如果上下文不存在事务,则使用无事务的方式执行。即:如果上下文有事务,则加入这个事务;否则直接执行,不会新创建事务;
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
// 如果当前上下文存在事务,则加入这个事务;如果上下文不存在事务,则报错;
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
// 每次都新创建一个事务。如果当前上下文有事务,则挂起上下文的事务,重新创建一个事务;如果当前上下文没有事务,新创建一个事务;
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
// 不支持事务执行。如果当前上下文存在事务,则挂起上下文事务;
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
// 无事务执行。如果当前上下文存在事务,则抛异常;
NEVER(TransactionDefinition.PROPAGATION_NEVER),
// 嵌套事务。如果上下文存在事务,则在嵌套的事务中执行;如果上下文没有事务,则新创建一个事务;
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
3.2 传播特性判断
Spring事务中的传播特性在AbstractPlatformTransactionManager类中进行判断,详见
传播特性判断的核心代码如下:
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// 抽象方法。如JpaTransactionManager.doGetTransaction(),创建一个JpaTransactionObject对象,开启一个新的Connection
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
definition = new DefaultTransactionDefinition();
}
// 如果事务存在,则检测传播行为并返回
if (isExistingTransaction(transaction)) {
// 找到现有事务->检查传播行为以了解行为方式
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// 检查事务属性中的超时属性,默认为-1
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'");
}
// 如果事务的传播特性为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED,
// 此时没有事务,所以需要创建新的事务
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 挂起事务,此处返回的suspendedResources为null
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
// 初始getTransactionSynchronization()为0,需要激活事务同步
// SYNCHRONIZATION_NEVER为2,表示不激活事务同步
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建一个DefaultTransactionStatus对象,传入刚创建的transaction对象,新开启一个连接
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开始事务
doBegin(transaction, definition);
// 准备同步,将事务相关信息保存到本地线程变量
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// 传播特性为PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER,此时没有事务,则不开启事务执行
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);
// 创建一个DefaultTransactionStatus对象,此处的transaction为null
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 如果事务的传播特性为PROPAGATION_NEVER,因为上下文存在事务,则抛异常
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);
// 创建一个DefaultTransactionStatus对象,此处的transaction为null
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对象,此处的transaction为新创建的事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事务
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 如果事务的传播特性为PROPAGATION_NESTED,因为上下文存在事务,则使用嵌套事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
// 如果支持savepoint保存点,则创建保存点
if (useSavepointForNestedTransaction()) {
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else { // 否则的话,创建新的事务
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
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);
// 继续执行事务
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
}
事务的传播特性判断在AbstractPlatformTransactionManager的getTransaction()和handleExistingTransaction()方法。
3.2.1 getTransaction()
getTransaction()方法主要执行如下:
1)执行抽象方法doGetTransaction(),获取一个事务对象。如如JpaTransactionManager.doGetTransaction(),创建一个JpaTransactionObject对象,开启一个新的Connection;
2)判断上下文是否存在事务,如果有,则执行handleExistingTransaction()方法;
3)如果没有事务,执行如下:
3.1)如果事务的传播特性为PROPAGATION_MANDATORY,则抛异常;
3.2)如果事务的传播特性为PROPAGATION_REQUIRED或PROPAGATION_REQUIRES_NEW或PROPAGATION_NESTED,此时没有事务,所以需要创建新的事务;
3.3)否则,传播特性为PROPAGATION_SUPPORTS或PROPAGATION_NOT_SUPPORTED或PROPAGATION_NEVER,此时没有事务,则不开启事务,继续执行;
3.2.2 handleExistingTransaction()
handleExistingTransaction()执行时,说明当前上下文存在事务,方法主要执行如下:
1)如果事务的传播特性为PROPAGATION_NEVER,因为上下文存在事务,则抛异常;
2)如果事务的传播特性为PROPAGATION_NOT_SUPPORTED,因为上下文存在事务,则挂起事务,继续执行;
3)如果事务的传播特性为PROPAGATION_REQUIRES_NEW,因为上下文存在事务,则挂起事务,新创建一个事务;
4)如果事务的传播特性为PROPAGATION_NESTED,因为上下文存在事务,则使用嵌套事务;
4.1)如果支持savepoint保存点,则创建保存点。如果保存点中的报异常,则只回滚保存点的事务;
4.2)如果不支持savepoint,则创建新事务;
小结
在实际的项目中,需要根据实际的业务需要,设置合理的传播特性,使用不当,不仅会导致事务失效,还可能导致数据不一致问题。
以上为本篇分享的全部内容,关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。
710

被折叠的 条评论
为什么被折叠?



