Sql-Server

UPLOCK 避免多次讀取

  • September 11, 2016

給定以下表結構…

Orders
======
OrderId int PK

OrderEvent
===========
OrderEventId int PK
OrderId int FK
EventTypeId int FK

我有多個並發程序選擇訂單,但每個訂單總體上只能讀取一次。因此,在檢索到訂單後,我需要在 OrderEvent 表中添加一行以標記已讀取訂單(EventTypeId = 1)。

所以我的想法是對閱讀進行以下查詢…

SELECT * 
FROM Orders o WITH (UPDLOCK) 
WHERE NOT EXISTS (SELECT * 
                 FROM OrderEvent oe 
                 WHERE oe.OrderId = o.OrderID 
                   AND EventTypeId = 1)

這在事務中執行,並在讀取後添加訂單事件行以將訂單標記為已讀取。

那麼問題來了,這樣能保證每個訂單只能檢索一次嗎?

我不確定的是何時將鎖放在訂單行上?是在評估 where 子句之前還是之後?

UPDLOCK 將阻止後續呼叫讀取已提取的訂單,但不允許後續呼叫讀取其他呼叫,因為它將等待讀取符合條件的所有行,並且您已明確告訴引擎您打算在此事務中更新它們。

如果您還添加了一個 READPAST 提示,它將允許後續呼叫獲取之前未提取的任何可用行。

SELECT * 
FROM Orders o WITH (UPDLOCK,READPAST) 
WHERE NOT EXISTS (SELECT * 
             FROM OrderEvent oe 
             WHERE oe.OrderId = o.OrderID 
               AND EventTypeId = 1)

引用自:https://dba.stackexchange.com/questions/48686