2011-02-07 62 views
3

我有一系列需要自動運行的T-SQL查詢。 (見下文)...目的是讓一個用戶一次檢索一個唯一的行,並防止其他用戶同時檢索同一行。TABLOCKX與SERIALIZABLE

到目前爲止,我已經看到了兩種可能的解決方案。 1)表提示(HOLDLOCK,TABLOCKX)和2)事務隔離級別(SERIALIZABLE)...

我的問題:

  1. 哪種選擇更好?

  2. 有沒有另一個/更好的解決方案?

DECLARE @recordId int; 

SELECT @recordId = MIN([id]) 
FROM Exceptions 
WHERE [status] = 'READY'; 

UPDATE Exceptions 
SET [status] = 'PROCESSING', 
    [username] = @Username 
WHERE [id] = @recordId; 

SELECT * 
FROM Exceptions 
WHERE [id] = @recordId; 

回答

7

在這種情況下,

  • HOLDLOCK = SERIALIZABLE =持續時間,併發
  • TABLOCKX =獨佔表鎖

的2個概念是不同的,並且你想要的也不是。

要做你想做的,到avoid race conditions,你需要強制一個非阻塞(READPAST)獨佔(UPDLOCK)行級別(ROWLOCK)鎖定。你也可以使用OUTPUT子句使它成爲原子的單個語句。這比例很好。

UPDATE 
    E 
SET 
    [status] = 'PROCESSING', [username] = @Username 
OUTPUT 
    INSERTED.* 
FROM 
    (
    SELECT TOP 1 id, [status], [username] 
    FROM Exceptions (ROWLOCK, READPAST, UPDLOCK) 
    WHERE [status] = 'READY' 
    ORDER BY id 
    ) E 

在一般情況下,鎖有3個方面

  • 粒度=什麼是鎖定=行,頁表(PAGLOCK, ROWLOCK, TABLOCK
  • 隔離級別=鎖定持續時間,併發(HOLDLOCK, READCOMMITTED, REPEATABLEREAD, SERIALIZABLE
  • 模式=共享/排他性(UPDLOCK, XLOCK

  • 「組合拳」,如NOLOCK, TABLOCKX
2

你所描述的典型隊列處理既不TABLOCKX,也不需要序列化,也不會實際工作。我建議你通過Using tables as Queues進行部分討論,討論什麼是可能的,哪些不可以。它的要點是:

  • 選擇合適的聚集鍵(!關鍵)
  • 使用OUTPUT子句
  • 使用READPAST