簡體   English   中英

Spring事務中REQUIRES_NEW和NESTED傳播行為的差異

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

前言

首先:

與Spring事務中的requires_new和嵌套傳播之間差異不重復 - 我讀了它,但我沒有找到我的問題的答案

題:

在閱讀了我提到的主題之后,我理解了物理交易數量中傳播水平的主要區別:
2 db事務 - 對於外部和內部方法的REQUIRES_NEW
1 db transaction - 用於NESTED for outer和for inner方法。 如果底層數據庫不支持保存點,它將無法工作

但是看起來邏輯從我的觀點來看是相同的。

如何理解在實踐中使用哪個級別? 任何用例了解它? 方便的行為差異的例子?

PS
我想其他事務差異有一些可見性,因為不同的事務提交時間。

PS2

另外我認為有性能差異:

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

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

對於那種情況,NESTED會更好,因為1長的物理交易而不是100500 + 1

我看到的巨大差異:

在嵌套的情況下:

  • 如果回滾外部事務,則也會回滾嵌套的tra。
  • 可見性 :如果db執行的MVCC很常見,
    • 嵌套的tra看到外部tra的先前更改。
    • 在提交外部之后,嵌套tra的更改將被視為已提交並且對其他tra可見。
  • 性能:請注意,外部事務的工作集由內部事務擴展。 因此更多的鎖,MVCC的更多preimage-storage,更長的redo-log-entry。

在requires_new的情況下:

  • 如果外部事務被回滾,則在外部tra的回滾的情況下,不會回滾內部tra的更改。
  • 可見性 :在MVCC的情況下,這是非常常見的,
    • 內部tra將看不到尚未提交的外部tra所做的更改。
    • 即使在提交外部tra之前,嵌套tra的更改也將在提交此內部tra后立即呈現為對其他tra提交並可見。 較少的鎖,但由於許多提交更多的外部操作,重做鎖中的記錄更多。

性能方面 ,如果其他因素不重要,您可以在交易規模和交易數量之間找到收支平衡點。 如果嵌套比requires_new快,那么問題沒有一般的答案。

正如你的例子所示,如果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()

如果你的內部邏輯獨立於外部邏輯,則使用Requires_new,如果不使用嵌套。

例如,您的外部方法可能正在處理包含大量記錄的作業,並調用持久作業狀態的內部方法(進度,警告和驗證錯誤)。 您希望內部方法事務是獨立的,並且其數據庫更改將立即保存,以便系統的其他部分可以顯示進度。 如果外部方法遇到異常,它的事務將回滾,但內部方法的事務不會。

當您需要對外部和內部更改進行持久化或同時回滾兩者時,您可能希望使用嵌套或從屬事務。 例如,您需要創建一個新用戶(使用“外部”服務)並保存其地址(使用“內部”服務)。 如果您的要求是用戶必須擁有地址,那么如果保存用戶或地址失敗,您希望回滾兩個更改。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM