2014-04-22 113 views
1

對於以下事務,偶爾會在爲同一訂單同時調用此事務時收到死鎖錯誤。更新聲明中的DeadLock和UPDLOCK提示的用法

BEGIN TRANSACTION 
     IF EXISTS (SELECT orderID FROM [Orders]WHERE [email protected]) 
     BEGIN 
     UPDATE [Orders] SET 
[orderXml] [email protected] 
     ,[updatedDateTime] = @updatedDateTime 
WHERE 
[orderId] = @OrderId AND @updatedDateTime > updatedDateTime 
     END 

if @@ROWCOUNT = 0 
     BEGIN 
      DELETE OrderLine 
      WHERE 
    [email protected] 
     END 

COMMIT TRANSACTION 

死鎖圖形:

<resource-list> 
     <keylock hobtid="72057594039042048" dbid="13" objectname="OrderDB.dbo.Orders" indexname="PK_Order" id="lockac2e8d80" mode="U" associatedObjectId="72057594039042048"> 
     <owner-list> 
      <owner id="process80736748" mode="U"/> 
     </owner-list> 
     <waiter-list> 
      <waiter id="process80739b88" mode="U" requestType="convert"/> 
     </waiter-list> 
     </keylock> 
     <keylock hobtid="72057594039042048" dbid="13" objectname=" OrderDB.dbo.Orders" indexname="PK_Order" id="lockac2e8d80" mode="U" associatedObjectId="72057594039042048"> 
     <owner-list> 
      <owner id="process80739b88" mode="S"/> 
     </owner-list> 
     <waiter-list> 
      <waiter id="process80736748" mode="X" requestType="convert"/> 
     </waiter-list> 
     </keylock> 
    </resource-list> 

PK_Order是訂單表的OrderId(VARCHAR)列中的主鍵。該表還在updatedDateTime(datetime2)列上獲得了Non聚集索引。

問題:當我在上面的更新語句中使用WITH(UPDLOCK)提示時,死鎖似乎消失了。 建議使用UPDLOCK提示還是應該將事務隔離級別設置爲可序列化。 在上面的delete語句中也可以使用UPDLOCK提示。

回答

1

這是一個經典的死鎖案例。訪問模式是可讀寫的。兩個trans讀,然後都寫不出來。

您採取「寫入」鎖定(UPDLOCK)的解決方案很好。使用UPDLOCK, ROWLOCK, HOLDLOCK,我認爲這是最好的例子。

SERIALIZABLE沒有幫助,因爲該模式仍然會被讀取然後寫入。

DELETE不需要額外的鎖定,因爲事務已經獲得對所討論的行的獨佔訪問權限。