有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在Spring事务中的行为差异需要新的和嵌套的传播

前言

首先:

它不是Differences between requires_new and nested propagation in Spring transactions的副本-我读了它,但我没有找到我问题的答案

问题:

在阅读了我提到的主题后,我了解到在物理事务计数方面传播级别之间的主要区别:
2 db事务-用于REQUIRES_NEW外部和内部方法
1 db事务-用于外部方法和内部方法的NESTED。如果基础数据库不支持保存点,它将不起作用

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

如何理解在实践中使用哪个级别?有了解它的用例吗?行为差异的简便例子

p.S.
我认为,由于事务提交时间不同,其他事务的差异也存在一些可见性

p.S.2

此外,我认为存在性能差异:

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

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

在这种情况下,嵌套将更好,因为1个长物理事务而不是100500+1


共 (2) 个答案

  1. # 1 楼答案

    我看到的最大区别是:

    在嵌套的情况下:

    • 如果回滚外部事务,则也回滚嵌套的tra
    • 可见性:如果db同时执行非常常见的MVCC,
      • 嵌套的tra可以看到外部tra的先前更改
      • 提交外部tra后,嵌套tra的更改将被提交,并对其他tra可见
    • 性能:请注意,外部事务的工作集会被内部事务扩展。因此,MVCC的锁越多,预映像存储越多,重做日志条目越长

    如果需要新的:

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

    对于性能,如果其他因素不重要,您可以在事务大小和事务编号之间找到平衡点。i、 m.O如果嵌套的速度比要求的快,那么这个问题没有一般的答案

  2. # 2 楼答案

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

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

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

    如果inner()有:

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

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


    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
    }
    

    显然REQUIRES_NEWNESTED只会保留来自成功的inner()调用的更改。不过,关键的区别在于NESTED,如果outer()中出现后续故障,仍然可以选择将其全部丢弃

    正如您所说的,另一个因素是可伸缩性——一些数据库可能不了解具有NESTED传播的父事务的大小


    此外,这可能值得一提——尽管我怀疑这只是为了在示例中清晰起见。直接调用this.inner()会绕过Spring事务顾问。需要允许它注入一个“建议bean”,以允许@Transactional注释在调用前后发挥其魔力-例如nextAutowiredBean.inner()