SQL Server:如何获取独占锁以防止竞争条件?

时间:2011-03-17 16:25:41

标签: sql sql-server transactions locking isolation-level

我有以下T-SQL代码:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION T1_Test

    /*This is a dummy table used for "locking" 
    and it doesn't contain any meaningful data.*/        
    UPDATE lockTable 
        SET ID = 1    
        WHERE ID = 1

    DECLARE @Count TINYINT 

    SELECT @Count = COUNT(*)
    FROM debugSP 

    WAITFOR DELAY '00:00:5';

    INSERT INTO debugSP 
        (DateCreated, ClientId, Result)
    SELECT 
        GETDATE(), @@SPID, @Count

COMMIT TRANSACTION T1_Test

我正在使用标记为注释的“锁定”黑客获取独占锁。

注意:使用TABLOCKX或UPDLOCK提示将不起作用,因为我通过拆分语句并在中间添加WAITFOR命令以进行测试来打破ATOMIC-ity。 我不想要那样的东西:

INSERT INTO debugSP (DateCreated, ClientId, Result)
SELECT GETDATE(), @@SPID, COUNT(*) 
FROM debugSP

这是运行两个同时会话(带锁表)后的正确结果

Id DateCreated           ClientId Result
-- ----------------------- -------- ------
 1 2011-03-17 15:52:12.287       66      0
 2 2011-03-17 15:52:24.534       68      1

这是使用锁定注释

运行代码的错误结果
Id DateCreated           ClientId Result
-- ----------------------- -------- ------
 1 2011-03-17 15:52:43.128       66      0
 2 2011-03-17 15:52:46.341       68      0

有没有更好的方法可以在没有这种黑客的情况下获得交易范围的独占锁?

2 个答案:

答案 0 :(得分:7)

我不确定您要发布的代码是做什么的。我假设您只是尝试序列化对该段代码的访问?如果是这样的话sp_getapplock应该做你需要的,而不是创建一个你只是用来锁定的新的虚拟表。

Details here

答案 1 :(得分:1)

您可以在具有可重复读取隔离的事务范围内使用锁定提示WITH(XLOCK,ROWLOCK)。在Serializable隔离时,默认情况下在读操作时获得独占锁,因此如果您需要特定事务并行执行,则可以在创建它时为该一个事务指定增加的序列化级别(您正在执行此操作;这不是不管怎么说,根据具体情况完成任务的方式。