我正在嘗試使用 hibernate 學習 JPA 并使用 MySQL 作為資料庫。
以我的理解,
LockModeType.OPTIMISTIC:在當前運行的事務結束時檢查物體版本。
REPEATABLE READ:同一事務中的所有一致性讀取讀取由該事務中的第一個此類讀取建立的快照
休眠中的 LockModeType.OPTIMISTIC 是否與 MySQL 的默認隔離級別不兼容?
假設我有以下代碼:
tx.begin();
EntityManager em = JPA.createEntityManager();
Item item = em.find(Item.class, 1, LockModeType.OPTIMISTIC);
// Assume the item here has version = 0
// Read the item fields etc, during that another transaction commits and made item version increased to version = 1
tx.commit(); // Here Hibernate should execute SELECT during flushing to check version,
// i.e SELECT version FROM Item WHERE id = 1
em.close();
我期望的是,在重繪 期間,Hibernate 會拋出 OptimisticLockException 因為專案的版本不再是 0。但是,由于隔離級別,在同一個事務中,Hibernate 仍然會看到 version = 0 中的專案并且不會觸發OptimisitcLockExcpetion。
我嘗試搜索,但之前似乎沒有人提出過這樣的問題,希望有人能幫助我清除對 OptimisticLock 的困惑。
uj5u.com熱心網友回復:
如果您的問題實際上是與以下陳述句相關的 HBN 實作(或 JPA 規范)中是否存在缺陷:
如果事務 T1 在版本化物件上呼叫 LockModeType.OPTIMISTIC 型別的鎖,則物體管理器必須確保以下兩種現象都不會發生:
- P1(臟讀):事務 T1 修改了一行。然后另一個事務 T2 在 T1 提交或回滾之前讀取該行并獲得修改后的值。事務 T2 最終提交成功;T1 是提交還是回滾以及它是在 T2 提交之前還是之后執行都無關緊要。
- P2(不可重復讀):事務 T1 讀取一行。另一個事務 T2 然后在 T1 提交之前修改或洗掉該行。兩個事務最終都成功提交。
鎖定模式必須始終防止現象 P1 和 P2。
那么答案是肯定的,您是對的:如果您根據某個物體狀態執行計算,但您沒有修改這些物體狀態,HBN 只會select version from ... where id = ...在交易結束時發出問題,因此它看不到其他交易的變化由于 RR 隔離級別。但是,我不會說 RC 隔離級別在這種特殊情況下表現更好:從技術角度來看它的行為更正確,但從業務角度來看它完全不可靠,因為它取決于時間,所以不要依賴 LockModeType.OPTIMISTIC - 它是設計不可靠并使用另一種技術,例如:
- 將來自不同域的資料存盤在不同的物體中
- 利用@OptimisticLock 注釋來防止在不需要時增加版本(實際上這會通過 HBN 注釋毒害您的域模型)
- 將一些屬性標記為
updatable=false并通過 JPQL 更新來更新它們以防止版本增加
uj5u.com熱心網友回復:
為了理解這一點,讓我們快速了解一下休眠樂觀鎖是如何作業的:
1:開始一個新的事務
2:通過 ID 找到一個物體(休眠問題 a
SELECT ... WHERE id=xxx;),例如可以有一個version計數13:修改物體
4:重繪 對資料庫的更改(例如,在提交事務之前自動觸發):
- 4.1: hibernate 發出
UPDATE ... SET ..., version=2 WHERE id=xxx AND version=1回傳更新行數的an - 4.2: hibernate 檢查是否有一行實際更新,如果沒有則拋出 StaleStateException
- 4.1: hibernate 發出
5:在例外情況下提交事務/回滾
使用repeatable_read 隔離級別,第一個SELECT建立SELECT相同事務的后續s 讀取的狀態(快照)。然而,這里的關鍵是,UPDATE它不是在建立快照操作,但該行的提交狀態(這可能已經被其他已提交的事務在此期間改變)。
因此,如果版本計數器同時已被另一個提交的事務更新,則更新實際上不會更新任何行,并且休眠可以檢測到這一點。
另請參閱:
https : //dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html 可
重復讀取隔離級別 SELECT vs UPDATE...WHERE
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/373507.html
上一篇:findbyID回傳optional。將此物件設定為另一個物件會導致錯誤
下一篇:無法在此ManagedType[com.company.domain.Statistics]上找到具有給定名稱[ANumber]的屬性
