Spring源码解析之事务传播特性

网友投稿 227 2022-10-22


Spring源码解析之事务传播特性

一、使用方式

可以采用Transactional,配置propagation即可。

打开org.springframework.transaction.annotation.Transactional可见默认传播特性是REQUIRED。

/**

* The transaction propagation type.

*

Defaults to {@link Propagation#REQUIRED}.

* @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()

*/

Propagation propagation() default Propagation.REQUIRED;

二、getTransaction

顾名思义,此项属性是在事务存在交互时生效。那么到底是如何生效的呢,核心源码位于org.springframework.transaction.support.AbstractPlatformTransactionManager。核心入口是getTransaction方法。

@Override

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {

Object transaction = doGetTransaction();

// Cache debug flag to avoid repeated checks.

boolean debugEnabled = logger.isDebugEnabled();

//

if (definition == null) {

// Use defaults if no transaction definition given.

definition = new DefaultTransactionDefinition();

}

//已经存在事务 根据事务传播特性进行处理

if (isExistingTransaction(transaction)) {

// Existing transaction found -> check propagation behavior to find out how to behave.

return handleExistingTransaction(definition, transaction, debugEnabled);

}

// Check definition settings for new transaction.

if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {

throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());

}

// No existing transaction found -> check propagation behavior to find out how to proceed.

//当前不存在事务 MANDATORY直接抛出异常

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

throw new IllegalTransactionStateException(

"No existing transaction found for transaction marked with propagation 'mandatory'");

}

//REQUIRED REQUIRES_NEW NESTED则会新建一个事务

else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

SuspendedResourcesHolder suspendedResources = suspend(null);

if (debugEnabled) {

logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);

}

try {

boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

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 {

xxx

}

}

可以看到,在当前不存在事务时,

MANDATORY 直接抛出异常

REQUIRED REQUIRES_NEW NESTED 自动新建一个事务。

那么存在事务时是如何处理的呢?

三、handleExistingTransaction

/**

* 处理已经存在事务的情况

* Create a TransactionStatus for an existing transaction.

*/

private TransactionStatus handleExistingTransaction(

TransactionDefinition definition, Object transaction, boolean debugEnabled)

throws TransactionException {

//NEVER 已经存在事务 直接抛出异常

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {

throw new IllegalTransactionStateException(

"Existing transaction found for transaction marked with propagation 'never'");

}

//NOT_SUPPORTED 注意prepareTransactionStatus方法参数传递事务的时候传递参数为null,所以是采用非事务方式运行。执行会挂起当前事务。

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

}

//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;

}

catch (RuntimeException | Error beginEx) {

resumeAfterBeginException(transaction, suspendedResources, beginEx);

throw beginEx;

}

}

//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 (debugEnablfOpslcOISed) {

logger.debug("Creating nested transaction with name [" + definition.getName() + "]");

}

// 支持的话则采用Savepoint 否则开启新事务 并不会挂起当前事务

if (useSavepointForNestedTransaction()) {

// Create savepoint within existing Spring-managed transaction,

// through the SavepointManager API implemented by TransactionStatus.

// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.

DefaultTransactionStatus status =

prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);

//注意此处会创建savePoint

status.createAndHoldSavepoint();

return status;

}

else {

// Nested transaction through nested begin and commit/rollback calls.

// Usually only for JTA: Spring synchronization might get activated here

// in case of a pre-existing JTA transaction.

boolean newSynchfOpslcOISronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

// 注意此处newTransaction属性设置为true,说明确实采用了创建新事务方式来实现

DefaultTransactionStatus status = newTransactionStatus(

definition, transaction, true, newSynchronization, debugEnabled, null);

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 currfOpslcOISentIsolationLevel = 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);

}

可以看到,当已经存在事务时,

NEVER 直接报错,不支持事务

NOT_SUPPORTED 默默按照非事务方式运行

REQUIRES_NEW 新建一个事务。

NESTED 处理嵌套事务 视情况采用savePoint或者新建事务。

其他的 加入当前事务

四、NESTED 嵌套事务

SavePoint

先简单说说SavePoint机制吧。这个也比较简单。

比如一个 事务比较复杂,容易出错。那么如果当前DB支持SavePoint的话,那么创建一个SavePoint就等于创建了一个快照,可以不用每次都回滚整个事务,仅回滚到指定的SavePoint即可。

五、个人理解

NESTED这个处理确实比较复杂。个人也查了很多资料。目前个人目前理解如下:

NESTED对于事务的处理主要在于级别不同。

REQUIRES_NEW创建的两个事务是平级的,一个事务的成功与否对另一个事务的成功与否不产生影响。

而NESTED创建的事务则名副其实,是受其父级事务影响的。

一句话总结就是,子事务的成功与否不影响父级事务的成功,但是父级事务的成功与否则会影响子事务的成功。

父事务回滚,子事务一定会滚。

子事务回滚,父事务不一定会滚。

六、总结

最后总结如下

名称

说明

PROPAGATION_REQUIRED

方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,否则开启新事务。 默认选项。

PROPAGATION_SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY

支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER

以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED

如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。需要JDBC3.0以上支持。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:这几个习惯,让我成为了高阶网络工程师。
下一篇:《2021年中国网络安全市场全景图》发布,宁盾强势上榜5大细分领域
相关文章

 发表评论

暂时没有评论,来抢沙发吧~