首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring事务中REQUIRES_NEW和嵌套传播行为的差异

问Spring事务中REQUIRES_NEW和嵌套传播行为的差异
EN

Stack Overflow用户
提问于 2018-10-21 18:08:26
回答 3查看 1.7K关注 0票数 7

前言

首先:

它不是new and nested propagation in Spring transactions的复制--我读过它,但是我没有找到的答案,我的问题

问题:

在阅读了我提到的主题之后,我理解了物理事务计数中传播级别之间的主要区别:

2 db事务-用于外部和内部方法的REQUIRES_NEW

1 db事务-用于外部方法和内部方法的NESTED。如果底层数据库不支持保存点,它将无法工作。

但从我的观点来看,逻辑是一样的。

如何理解在实践中使用哪个层次?有什么用例来理解它吗?行为差异的方便例子?

P.S.

我认为,由于事务提交时间不同,其他事务之间的差异也有一些可见性。

P.S.2

此外,我认为性能上也有差异:

代码语言:javascript
复制
@Transactional
public void outer(){
    for(int i=0;i<100500;i++){
        inner();
    }   
}

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

对于这种情况,嵌套将更好,因为有一个长的物理事务而不是100500+1。

EN

回答 3

Stack Overflow用户

发布于 2018-11-01 23:30:51

在您的示例中,如果inner()有:

代码语言:javascript
复制
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void inner(){
   //some logic
}

然后,如果它从outer()循环中的第二个调用中抛出一个异常,那么来自第一个调用的更改就已经提交--由它的REQUIRES_NEW提交。

如果inner()有:

代码语言:javascript
复制
@Transactional(propagation=Propagation.NESTED)
public void inner(){
   //some logic
}

然后,将回滚第一个调用中的更改--因为outer()中没有catch块。

inner()上传播级别真正重要的一点是,outer()循环是否要处理inner()中的异常?

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

显然,REQUIRES_NEW和NESTED都只会对成功的inner()调用进行更改。但是,关键的区别在于,对于NESTED,如果outer()出现后续故障,仍然可以将其全部丢弃。

正如您所说,另一个因素是可伸缩性--一些数据库可能不喜欢使用NESTED传播的父事务的大小。

而且,这可能是值得说的--尽管我怀疑它只是为了使例子更清晰。直接调用this.inner()将绕过Spring事务顾问。需要允许它注入一个“建议bean”,以允许@Transactional注释在调用之前和之后执行它的魔术-例如,nextAutowiredBean.inner()。

票数 5
EN

Stack Overflow用户

发布于 2018-10-22 20:58:11

我看到的巨大差异是:

在嵌套情况下:

  • 如果外部事务被回滚,嵌套的tra也会回滚。
  • 可见性:如果db执行MVCC,这是相当常见的,同时,
    • 嵌套的tra可以看到外部tra先前的更改。
    • 在外部提交之后,嵌套的tra的更改将被看到、提交并对其他tras可见。

​

  • 性能:请注意,外部事务的工作集由内部事务扩展。因此,更多的锁,更多的预映像存储的MVCC,一个更长的重做日志条目。

就requires_new而言:

  • 如果外部事务被回滚,则在外部tra回滚的情况下,内部tra的更改将不会回滚。
  • 可见性:在MVCC的情况下,这是相当普遍的,同时,
    • 内部tra将不会看到尚未提交的外部tra所做的更改。
    • 嵌套tra的更改将在此内部tra提交后立即被其他tras看到并可见,甚至在外部tra提交之前也是如此。锁较少,但由于许多锁提交更多外部操作,重做锁中记录更多.

​

如果是performance,,如果其他因素不重要,您可以在事务大小和事务号之间找到平衡点。如果嵌套比requires_new更快,那么这个问题就没有一般的答案了。

票数 3
EN

Stack Overflow用户

发布于 2018-11-04 05:09:06

如果您的内部逻辑独立于外部逻辑,那么使用Requires_new,如果不使用嵌套的。

例如,外部方法可能正在处理包含大量记录的作业,并调用持久作业状态的内部方法(进度、警告和验证错误)。您希望内部方法事务是独立的,并且它的db更改将立即保存,以便系统的其他部分可以显示进度。如果外部方法遇到异常,它的事务将回滚,但内部方法的事务不会。

当需要将外部和内部更改保持在一起或两者一起回滚时,您可能希望使用嵌套或依赖的事务。例如,您需要创建一个新用户(使用“外部”服务)并保存他们的地址(使用“内部”服务)。如果您的需求是用户,则必须有一个地址,那么如果保存用户或地址失败,您希望两个更改都回滚。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52918369

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档