簡體   English   中英

Spring Data:重試時回滾事務

[英]Spring Data: rollback transaction on retry

有一個實體:

@Entity
class A {
    ...
    @Version
    int version; 
}

A實例更新的樂觀的方式來實現:

@Transactional(rollbackFor = {StaleStateException.class})
@Retryable(value = {StaleStateException.class})
public void updateA() {
    A a = findA();
    B b = new B();
    // Update "a" somehow
    a.update();
    // "b" is saved on each retry!
    save(b);
}

如注釋中所述,似乎發生StaleStateException時事務不會回滾,因此每次重試時都會保存B實例。

是否可以在重試時回滾事務?

期望的行為是b僅在全成保存a更新。

我認為它可能與@Retryable配置有關。

正如文檔所述https://docs.spring.io/spring-batch/trunk/reference/html/retry.html#statelessRetry一樣 ,無狀態可重試只不過是一個循環,它一直調用相同的方法直到它成功。

問題是,每次失敗時,第一個被調用的攔截器都是可重試的,不會重新拋出異常,因此它永遠不會到達@Transactional

所以會發生的是,每次重試都將遵循默認的事務傳播,這將在上下文中重用相同的已打開事務和new B()

您可以通過調試檢查我是否在正確的線索上:如果您輸入第二次重試並發現A在更新塊之前已經更新,那么我應該是正確的。

您可以通過兩種方式修復:

將兩個塊分開(首先使用嵌套事務重試)

@Retryable(value = {StaleStateException.class})
public void retryableUpdate() {
   updateA();
}

@Transactional(rollbackFor = {StaleStateException.class})
public void updateA() {
    A a = findA();
    B b = new B();
    // Update "a" somehow
    a.update();
    // "b" is saved on each retry!
    save(b);
}

這樣事務就會先回滾。

或者您可以關注文檔並使用有狀態重試https://docs.spring.io/spring-batch/trunk/reference/html/retry.html#statefulRetry

暫無
暫無

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

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