简体   繁体   English

Spring事务中REQUIRES_NEW和NESTED传播行为的差异

[英]Differences in behaviour of REQUIRES_NEW and NESTED propagation in Spring transactions

Preface 前言

First of all: 首先:

It is not duplicate of Differences between requires_new and nested propagation in Spring transactions - I read it but I didn't found answer to my question 与Spring事务中的requires_new和嵌套传播之间差异不重复 - 我读了它,但我没有找到我的问题的答案

Question: 题:

After reading topic I mentioned I understood that main difference between propagation levels in count of physical transactions: 在阅读了我提到的主题之后,我理解了物理交易数量中传播水平的主要区别:
2 db transactions- for REQUIRES_NEW for outer and for inner method 2 db事务 - 对于外部和内部方法的REQUIRES_NEW
1 db transaction - for NESTED for outer and for inner method. 1 db transaction - 用于NESTED for outer和for inner方法。 It will not work if underlying database doesn't support savepoints 如果底层数据库不支持保存点,它将无法工作

But looks like logic will be the same from my point if view. 但是看起来逻辑从我的观点来看是相同的。

How to understand which level to use in practise? 如何理解在实践中使用哪个级别? Any use cases to understand it? 任何用例了解它? Handy examples of behavioural differences? 方便的行为差异的例子?

PS PS
I suppose there are some visibility for other transactions differences because different transaction commit time. 我想其他事务差异有一些可见性,因为不同的事务提交时间。

PS2 PS2

Also I suppose there are performance difference: 另外我认为有性能差异:

@Transactional
public void outer(){
    for(int i=0;i<100500;i++){
        inner();
    }   
}

@Transactional
public void inner(){
   //some logic
}

For that case NESTED will be better because of 1 long physical transaction instead of 100500+1 对于那种情况,NESTED会更好,因为1长的物理交易而不是100500 + 1

The big differences I see: 我看到的巨大差异:

in case of nested: 在嵌套的情况下:

  • If the outer transaction is rolled back,the nested tra is rolled back as well. 如果回滚外部事务,则也会回滚嵌套的tra。
  • visibility : if the db does MVCC that is quite common meanwhile, 可见性 :如果db执行的MVCC很常见,
    • the nested tra sees the previous changes of the outer tra. 嵌套的tra看到外部tra的先前更改。
    • changes of the nested tra will be seen committed and visible to other tras after commit of the outer. 在提交外部之后,嵌套tra的更改将被视为已提交并且对其他tra可见。
  • performance: be aware, that the working set of the outer transactions gets expanded by the inner transactions. 性能:请注意,外部事务的工作集由内部事务扩展。 So more locks, more preimage-storage for MVCC, a longer redo-log-entry. 因此更多的锁,MVCC的更多preimage-storage,更长的redo-log-entry。

In case of requires_new: 在requires_new的情况下:

  • If the outer transaction is rolled back, the changes of the inner tra will not be rolled back in case of rolback of the outer tra. 如果外部事务被回滚,则在外部tra的回滚的情况下,不会回滚内部tra的更改。
  • visibility : in case of MVCC that is quite common meanwhile, 可见性 :在MVCC的情况下,这是非常常见的,
    • the inner tra will not see changes done by the yet uncommitted outer tra. 内部tra将看不到尚未提交的外部tra所做的更改。
    • changes of the nested tra will be seen committed and visible to other tras immediately after commit of this inner tra, even before the commit of the outer tra. 即使在提交外部tra之前,嵌套tra的更改也将在提交此内部tra后立即呈现为对其他tra提交并可见。 Less locks, but because of the many commits more external operations, more records in the redo-lock. 较少的锁,但由于许多提交更多的外部操作,重做锁中的记录更多。

In case of performance , if the other factors are not important, you can find a break even between transaction size and transaction number. 性能方面 ,如果其他因素不重要,您可以在交易规模和交易数量之间找到收支平衡点。 imO there is no general answer to the question, if nested is faster than requires_new. 如果嵌套比requires_new快,那么问题没有一般的答案。

As it stands in your example, if inner() had: 正如你的例子所示,如果inner()有:

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void inner(){
   //some logic
}

Then if it threw an exception from the second call in the outer() loop, the changes from the first call would have already been committed - by its REQUIRES_NEW . 然后,如果它从outer()循环中的第二个调用中抛出异常,则第一个调用的更改将已经由其REQUIRES_NEW提交。

If inner() had: 如果inner()有:

@Transactional(propagation=Propagation.NESTED)
public void inner(){
   //some logic
}

Then the changes from the first call would be rolled back - because there is no catch block in outer() . 然后将回滚第一次调用的更改 - 因为outer()没有catch块。


The point where the propagation level on inner() really starts to matter is if the outer() loop is going to handle exceptions in inner() : inner()上的传播级别真正开始重要的一点是,如果outer()循环将处理inner()异常:

@Transactional
public void outer() {
    for (int i = 0; i < 100500; i++) {
        try {
            inner();
        } catch (Exception ex) {
            // Report and continue
        }
    }
    // Something else that could fail
}

Clearly both REQUIRES_NEW and NESTED would only keep changes from the successful inner() calls. 很明显, REQUIRES_NEWNESTED只会保留对成功的inner()调用的更改。 The key difference though is that with NESTED , there is still the option to throw it all away if there is a subsequent failure in outer() . 但关键的区别在于,使用NESTED ,如果outer()存在后续故障,仍然可以选择将其全部丢弃。

As you say, the other factor is scalability - some databases may not appreciate the size of the parent transaction with NESTED propagation. 如您所说,另一个因素是可伸缩性 - 某些数据库可能无法理解具有NESTED传播的父事务的大小。


Also, it might be worth saying - though I suspect it was just aiming for clarity in the example. 此外,它可能值得一说 - 尽管我怀疑它只是为了明确示例。 Calling this.inner() directly is bypassing the Spring transaction advisor. 直接调用this.inner()绕过Spring事务顾问。 It needs to be allowed to inject an 'advised bean' to allow the @Transactional annotation to do its magic before and after the call - eg nextAutowiredBean.inner() . 需要允许注入“建议的bean”以允许@Transactional注释在调用之前和之后执行其魔法 - 例如nextAutowiredBean.inner()

If your inner logic is independent of the outer logic then use Requires_new, if not use nested. 如果你的内部逻辑独立于外部逻辑,则使用Requires_new,如果不使用嵌套。

For example, your outer method may be processing a job containing a large number of records and calling an inner method that persists job status (progress, warnings and validation errors). 例如,您的外部方法可能正在处理包含大量记录的作业,并调用持久作业状态的内部方法(进度,警告和验证错误)。 You would want the inner methods transaction to be independent, and its db changes to be saved immediately so some other part of the system could display the progress. 您希望内部方法事务是独立的,并且其数据库更改将立即保存,以便系统的其他部分可以显示进度。 If the outer method encounters an exception, it's transaction would rollback, but the inner method's transactions would not. 如果外部方法遇到异常,它的事务将回滚,但内部方法的事务不会。

You would want to uses nested or dependent transactions when you need the outer and inner changes to either both be persisted or both be rolled back together. 当您需要对外部和内部更改进行持久化或同时回滚两者时,您可能希望使用嵌套或从属事务。 For example, you need to create a new user (using the "outer" service) and save their address (using the "inner" service). 例如,您需要创建一个新用户(使用“外部”服务)并保存其地址(使用“内部”服务)。 If your requirements are a user must have an address, then if the saving the user or address fails you want both changes to be rolled back. 如果您的要求是用户必须拥有地址,那么如果保存用户或地址失败,您希望回滚两个更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring 事务中 requires_new 和嵌套传播的区别 - Differences between requires_new and nested propagation in Spring transactions 循环传播新事务(使用REQUIRES_NEW)不能按预期方式进行 - Propagation of new transactions (using REQUIRES_NEW) in a loop is not working as expected Spring 事务从 NOT_SUPPORTED 到 REQUIRES_NEW 的传播 - Spring Transaction Propagation from NOT_SUPPORTED to REQUIRES_NEW Spring 事务:从带有 requires 的方法调用的带有 requires_new 的方法 - Spring transactions: Method with requires_new called from a method with requires Spring数据gemfire不支持REQUIRES_NEW个事务 - REQUIRES_NEW transactions in not supported by Spring data gemfire Propagation Required 和 Requires_new 的示例 - Examples for Propagation Required and Requires_new 使用Tx传播丢失了有关Hibernate的更新REQUIRES_NEW - Lost updates on Hibernate using Tx propagation REQUIRES_NEW 为什么即使在Spring服务类的第二种方法中传播= Propagation.REQUIRES_NEW时,事务也会回滚? - Why are the transactions rolled back even when propagation=Propagation.REQUIRES_NEW in second method in Spring service class? EJB Transactions属性:NOT_SUPPORTED和REQUIRES_NEW - EJB Transactions attribute: NOT_SUPPORTED and REQUIRES_NEW Spring Propagation.REQUIRES_NEW - Spring Propagation.REQUIRES_NEW
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM