2009-06-02 36 views
36

我有一個通過存儲過程被多個訂單處理器訪問的訂單隊列。每個處理器都會傳入一個唯一的ID,用於鎖定下一個20個訂單以供自己使用。存儲過程然後將這些記錄返回給訂單處理器以執行操作。SQL Server進程隊列爭用條件

有些情況下,多處理器能夠檢索相同的'OrderTable'記錄,他們試圖同時操作它。這最終導致過程中稍後拋出錯誤。

我的下一步行動是讓每個處理器抓取所有可用的訂單,並循環處理處理器,但我希望簡單地使這部分代碼線程安全,並允許處理器隨時抓取記錄。

如此明確 - 任何想法爲什麼我遇到這種競爭條件,以及我如何解決問題。

BEGIN TRAN 
    UPDATE OrderTable WITH (ROWLOCK) 
    SET  ProcessorID = @PROCID 
    WHERE OrderID IN (SELECT TOP (20) 
             OrderID 
           FROM OrderTable WITH (ROWLOCK) 
           WHERE ProcessorID = 0) 
COMMIT TRAN 


SELECT OrderID, ProcessorID, etc... 
FROM OrderTable 
WHERE ProcessorID = @PROCID 
+4

@Keltex

:很顯然,他想知道如何重寫此存儲過程,以便它不會導致兩個處理器處理相同的記錄。 – Welbog 2009-06-02 14:30:49

回答

48

編輯:

我用Google搜索來檢查我的回答:"Processing Data Queues in SQL Server with READPAST and UPDLOCK"。自從我閱讀並使用該解決方案已經有數年了。

原文:

如果您使用READPAST提示,然後鎖定的行被跳過。你已經使用了ROWLOCK,所以你應該避免鎖升級。正如我發現的那樣,您還需要UPDLOCK。

所以處理1門的鎖20行,處理2將在未來20,過程3需要的行41至60,等等

更新還可以寫成如下:

UPDATE TOP (20) 
    foo 
SET 
    ProcessorID = @PROCID 
FROM 
    OrderTable foo WITH (ROWLOCK, READPAST, UPDLOCK) 
WHERE 
    ProcessorID = 0 

刷新, 2011年10月

如果您一次需要SELECT和UPDATE,可以使用OUTPUT子句更優雅地完成此操作。

+0

有趣...我會試試這個 – 2009-06-02 15:40:08