TABLOCKX与SERIALIZABLE

时间:2011-02-07 18:17:14

标签: sql sql-server tsql

我有一系列需要以原子方式运行的T-SQL查询。 (见下文)...目的是允许1个用户一次检索一个唯一的行,并防止其他用户同时检索同一行。

到目前为止,我已经看到两种可能的解决方案。 1)表提示(HOLDLOCK,TABLOCKX)和2)事务隔离级别(SERIALIZABLE)...

我的问题:

  1. 哪个选项更好?

  2. 还有其他/更好的解决方案吗?

  3. 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 个答案:

答案 0 :(得分:7)

在这种情况下,

  • HOLDLOCK = SERIALIZABLE =持续时间,并发
  • TABLOCKX =独家桌锁

这两个概念是不同的,也不是你想要的。

要执行您想要的操作,要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

答案 1 :(得分:2)

您正在描述典型的队列处理,既不需要tablockx也不需要序列化,也不会实际工作。我建议你过去Using tables as Queues进行部门讨论,讨论可行的和不可行的。它的要点是:

  • 选择合适的群集密钥(严重!)
  • 使用OUTPUT子句
  • 使用READPAST