簡體   English   中英

如何暫時禁用 Hibernate 實體版本檢查?

[英]How to temporarily disable the Hibernate entity version checking?

我有一個顯示所有聯系人的頁面。 這只是只讀頁面,我所做的只是遍歷某個組的所有聯系人並顯示它們:

//Not lazy load of contacts, I cannot use lazy loading
List<Contact> contacts = someService.getContacts(groupId);

for (Contact contact : contacts) {
    //add contact properties to the model to be displayed later
}

同時,我可能有一個單獨的后台線程來更新其中一個聯系人。 該線程更新了一個我不打算顯示的字段,所以在這種情況下我對數據不同步完全沒問題。

問題是 Hibernate 將更新聯系人的版本號並將其提交到我的數據庫(當后台線程完成時)。 因此,當我的 for 循環遇到這樣的對象時,將拋出以下異常。

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

這完全沒問題。 有沒有辦法在通過休眠的集合迭代期間禁用對象的版本檢查? 當我說禁用時,我的意思是在這個特定的場景中,在這個特定的 for 循環中? 但不是其他情況。

我認為這是因為底層集合是AbstractPersistentCollection並且它的迭代器將使用相應的 db 值檢查每個成員的版本。

您不能基於會話禁用樂觀鎖定,但有一些替代方法可以處理這種情況:

  1. 你可以切換到無版本樂觀鎖
  2. 您可以將多個實體片段映射到同一個表,並且您可以擁有一個片段,該片段僅包含特定業務案例所需的列並且沒有版本。 這樣你就可以繞過常規的實體樂觀鎖定檢查。

如果您正在執行只讀操作,則不應收到 StaleObjectStateException。 當您使用陳舊的數據進行更新並且 Hibernate 使用版本信息檢測它時,會拋出此異常。

因此,請檢查您的代碼並確保您沒有從顯示聯系人的只讀操作中進行任何不需要的更新。

除了其他答案中描述的解決方案之外,我還可以提出以下兩種解決方案:

  • 在線程中使用native sql update來更新Contact實體,不要增加版本號。
  • 將更新的字段提取到單獨的實體中,並且不要在該實體中包含 @Version。 在更新Contacts的正常事務(由最終用戶請求觸發)中,使用OPTIMISTIC_FORCE_INCREMENT提示。 即使您只更新提取的實體,此提示也會強制Contact版本號遞增。 提到的另一個線程可以在沒有任何提示的情況下更新提取的實體。

兩種解決方案都有缺點,對我來說它們看起來同樣丑陋。 對於其他答案中提到的解決方案,我也有同樣的感覺。 我相信 JPA 應該在如何處理樂觀版本控制方面提供更大的靈活性。

暫無
暫無

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

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