[英]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");
}
}
有時這段代碼打印“不在數據庫中”,而我期望它總是打印“在數據庫中”。 我的問題是:
我正在考慮僅在 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.