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

作者:为啥我就不胖呢 时间:2021-08-14 16:49:39 

一、使用方式

可以采用Transactional,配置propagation即可。
打开org.springframework.transaction.annotation.Transactional可见默认传播特性是REQUIRED


/**
* The transaction propagation type.
* <p>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 (debugEnabled) {
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 newSynchronization = (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 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);
}

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

  • 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以上支持。

来源:https://blog.csdn.net/chenpengjia006/article/details/117256167

标签:Spring,事务,传播特性
0
投稿

猜你喜欢

  • 有关Java中的BeanInfo介绍

    2023-08-05 00:13:42
  • 使用Java方法配置Spring代码解析

    2023-07-15 09:20:59
  • Java8方法引用及构造方法引用原理实例解析

    2022-07-24 08:21:22
  • Android实现GridView中ImageView动态变换的方法

    2022-06-21 06:16:55
  • Spring Boot2如何构建可部署的war包

    2023-11-29 06:40:59
  • C#实现根据年份计算生肖属相的方法

    2023-04-01 01:12:06
  • C# 无边框窗体之窗体移动实现代码

    2021-07-22 04:36:48
  • c#中的浮点型转整形的舍取 四舍五入和银行家舍入实现代码

    2023-01-10 02:04:41
  • idea中如何去掉不想commit的文件

    2021-11-09 15:51:30
  • 关于@MapperScan包扫描的坑及解决

    2023-02-13 02:45:46
  • idea生成类注释和方法注释的正确方法(推荐)

    2022-09-11 03:45:14
  • 使用@pathvariable与@requestparam碰到的一些问题及解决

    2023-11-27 16:30:34
  • ViewPager实现漂亮的引导页

    2022-12-27 21:56:58
  • Druid(新版starter)在SpringBoot下的使用教程

    2021-07-03 20:25:18
  • 如何使用Java给您的图片瘦身之Thumbnailator技术

    2023-10-31 10:25:52
  • Docker学习之基于Dockerfile搭建JAVA Tomcat运行环境的方法

    2022-02-13 17:42:00
  • android预置默认的语音信箱号码具体实现

    2022-08-22 07:51:59
  • Java 实现FTP服务实例详解

    2023-06-18 10:45:25
  • Mybatis整合达梦数据库的完整步骤记录

    2023-11-23 07:15:37
  • JPA多数据源分布式事务处理方案

    2023-08-09 03:50:06
  • asp之家 软件编程 m.aspxhome.com