2011-02-07 49 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