2017-10-18 154 views
0

我很好奇hibernate樂觀鎖(專用版本的方式),我檢查了hibernate源代碼,它告訴它在當前事務提交之前檢查版本,但是如果在查詢之後發生了另一個事務DB中的版本列(在很短的時間間隔內),那麼當前交易認爲沒有變化,所以舊的交易將被錯誤地替換。hibernate樂觀鎖機制

EntityVerifyVersionProcess.java

@Override 
    public void doBeforeTransactionCompletion(SessionImplementor session) { 
     final EntityPersister persister = entry.getPersister(); 

     if (!entry.isExistsInDatabase()) { 
      // HHH-9419: We cannot check for a version of an entry we ourselves deleted 
      return; 
     } 

     final Object latestVersion = persister.getCurrentVersion(entry.getId(), session); 
     if (!entry.getVersion().equals(latestVersion)) { 
      throw new OptimisticLockException(
        object, 
        "Newer version [" + latestVersion + 
          "] of entity [" + MessageHelper.infoString(entry.getEntityName(), entry.getId()) + 
          "] found in database" 
      ); 
     } 
    } 

是這樣的情況下可能的?

希望有DB領域的專家誰會幫助我。

非常感謝。

+0

這會使它破碎和無用。不是一個很好的廣告「使用樂觀鎖定,它通常不會損壞您的數據!」。 – Kayaman

+0

嗯,其實我不認爲這是一個重複的問題,這個問題是關於樂觀鎖機制,但我不是... – user2015063

+0

你不是什麼?這似乎正是你在說什麼,不,沒有事情打破的機會。如果樂觀鎖定失敗,一個事務將被回滾。 – Kayaman

回答

1

基於對代碼的快速瀏覽,EntityVerifyVersionProcess用於讀取事務,因此不存在涉及數據丟失的可能性。這隻會檢查當事務提交時,它不會返回已經陳舊的數據。有了READ COMMITTED的交易,我想這可能返回的數據即刻會過時,但很難說,沒有進入細節。

寫交易另一方面使用EntityIncrementVersionProcess,這是一個完全不同的野獸,沒有任何競爭條件的機會。

public void doBeforeTransactionCompletion(SessionImplementor session) { 
    final EntityPersister persister = entry.getPersister(); 
    final Object nextVersion = persister.forceVersionIncrement(entry.getId(), entry.getVersion(), session); 
    entry.forceLocked(object, nextVersion); 
} 
+0

,所以它(OptimisticLock)使用「SELECT xxx FOR UPDATE」方法來鎖定,而不是在開始時鎖定長事務的記錄,這很有意義,謝謝你的幫助。 – user2015063

+0

不,沒有選擇更新,這將*在交易期間鎖定記錄。只是內部工作並不簡單,問題中的代碼不處理*更新*,只有*選擇*。如果你正在執行更新,那麼還有其他'* Process'類參與,但我不知道內部工作如此順利,以至於我可以準確解釋流程的流程。在某些時候,內部有'update foo WHERE version = @ oldversion',如果版本已經增加,則會失敗,並且會避免db中的任何可能的競爭條件。 – Kayaman

+0

我明白了,要研究代碼細節 – user2015063