簡體   English   中英

@Transactional 方法結束后數據庫不會立即更改

[英]Database is not changed immediately after the @Transactional method ends

我有一個 Java、Spring 數據應用程序和一個 PostgreSQL 數據庫,我的服務層中有一個與此類似的代碼:

public void method1() {
    PersonDto dto = method2();
    method3(dto);
}

@Transactional
public PersonDto method2() {
    Person p1 = personRepository.saveAndFlush(new Person());
    return createPersonDto(p1);
}

@Transactional
public void method3(PersonDto p1) {
    Person p2 = personRepository.findById(p1.getId());
    if (p2 == null) {
        System.out.println("Not in the DB");
    } else {
        System.out.println("In the DB");
    }
}

有時這段代碼打印“不在數據庫中”,而我期望它總是打印“在數據庫中”。 我的問題是:

  1. 這個 saveAndFlush 甚至是必要的? 因為我沒有在同一個事務中重復使用那個實體,我想它會和保存有同樣的效果,對吧?
  2. 如何保證method2 的修改在method 3 調用之前提交? 所以它總是打印“在數據庫中”?
  3. 我正在將我的實體轉換為 DTO 的事實是什么搞砸了? 也許如果我傳遞實體本身它會正常工作?

我正在考慮僅在 method1 中使用 @Transactional,或者將 method3 中的 @Transactional 替換為 @Transactional(isolation = Isolation.READ_UNCOMMITTED)。 有什么建議嗎?

我可以看到您獲得所描述結果的幾個原因。

一種可能性是@Transactional不一定意味着“在完全獨立的事務中執行此方法”。 默認傳播是REQUIRED ,如果一個已經處於活動狀態,它將使用現有事務。 因此,如果在先前打開事務的堆棧中調用method2() ,則在提交原始事務之前,它不會創建新事務(因此不會提交新實體)。 如果發生這種情況,一種解決方案是將傳播更改為REQUIRES_NEW

@Transactional(propagation = REQUIRES_NEW)

另一種可能性(似乎更有可能)是這些方法都在同一個 class 中。要理解失敗的原因,您必須了解 Spring 如何實現@Transactional (以及大多數其他行為注釋)的處理:使用代理。 這意味着只有通過代理的方法調用才能獲得事務行為。 這是典型的場景,當一個 object 調用它對另一個的引用時; 該引用實際上是對代理的引用,它攔截調用並將行為(在本例中為事務性)包裝在調用周圍。 然而,當在同一個實例中調用方法時,沒有代理在起作用(Spring 不會/不能用對代理的引用替換this ),因此沒有事務行為。

有幾種方法可以解決這個問題,但首先我會考慮如何重構我的類和方法來避免它。 如果這不合理,則在此 SO Q&A中討論諸如 AspectJ、 TransactionTemplate以及其他一些想法之類的內容。


附錄:這個問題及其答案還討論了解決代理問題的選項。

暫無
暫無

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

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