TABLOCKX与SERIALIZABLE的区别

4
我有一系列需要原子地运行的 T-SQL 查询(见下文)...目的是允许一个用户每次检索单个唯一行,并防止其他用户同时检索同一行。
到目前为止,我看到了两种可能的解决方案。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;
2个回答

8
在这种情况下,
  • HOLDLOCK = SERIALIZABLE = 持续时间、并发性
  • TABLOCKX = 一个排他的表锁

这两个概念都不同,也都不能达到你想要的效果。

要达到你想要的效果,即避免竞态条件,你需要强制进行非阻塞(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

一般来说,锁有三个方面:
  • 粒度 = 锁定的内容 = 行、页、表 (PAGLOCK, ROWLOCK, TABLOCK)
  • 隔离级别 = 锁定持续时间、并发性 (HOLDLOCK, READCOMMITTED, REPEATABLEREAD, SERIALIZABLE)
  • 模式 = 共享/独占 (UPDLOCK, XLOCK)

还有

  • "组合" 例如 NOLOCK, TABLOCKX

2
您正在描述典型的队列处理,既不需要tablockx,也不需要serializable,并且它们实际上也不起作用。我建议您阅读将表用作队列,深入讨论可能和不可能的内容。其要点如下:
  • 选择适当的聚集键(至关重要!)
  • 使用OUTPUT子句
  • 使用READPAST

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接