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设计模式之模版方法模式简介

    2023-07-16 14:58:32
  • 浅谈Android 指纹解锁技术

    2023-06-04 18:59:06
  • Java 序列化和反序列化实例详解

    2023-11-23 04:43:44
  • 深入浅出MappedByteBuffer(推荐)

    2023-11-14 19:59:43
  • IntelliJ IDEA(2019)安装破解及HelloWorld案例(图文)

    2022-07-01 22:43:39
  • openFeign服务之间调用保持请求头信息处理方式

    2022-11-07 23:45:21
  • 在SpringBoot中通过jasypt进行加密解密的方法

    2023-11-15 21:29:23
  • Java 用Prometheus搭建实时监控系统过程详解

    2023-09-06 12:07:40
  • Mybatis通过Spring完成代理类注入的流程分析

    2023-10-25 00:55:55
  • C#操作INI配置文件示例详解

    2021-11-06 11:03:01
  • 高可用架构etcd选主故障主备秒级切换实现

    2022-08-08 23:40:48
  • C#单例模式(Singleton Pattern)详解

    2021-12-30 05:55:03
  • Android使用ViewPager实现图片滑动预览效果

    2023-02-15 15:28:28
  • 关于Java中BeanMap进行对象与Map的相互转换问题

    2023-09-18 07:25:36
  • Java编程复用类代码详解

    2021-09-13 10:06:34
  • 解决idea中yml文件图标问题及自动提示失效的情况

    2021-06-08 14:59:42
  • 两个surfaceView实现切换效果

    2021-10-04 15:18:52
  • C#类中方法的执行顺序是什么

    2022-07-01 03:55:15
  • 记一次公司JVM堆溢出抽丝剥茧定位的过程解析

    2023-11-09 13:11:24
  • java显示当前运行时的参数(java运行参数)

    2023-09-07 10:03:22
  • asp之家 软件编程 m.aspxhome.com