使用XLOCK ROWLOCK选择TSQL死锁

时间:2017-04-11 19:29:48

标签: sql sql-server tsql deadlock database-deadlocks

简单问题 - 我在SQL Server表中有300k任务,我希望多个进程逐个选择它们,处理它们并保存结果。

我不时会在拣货和储蓄方面陷入僵局。

我需要确保两个进程不会选择相同的任务。因此,我使用XLOCK并在完成任务后,我将状态从1-Created更改为2-Started,之后将其处理为3-Completed。

此外,我的任务(tblTasksSets)与tblGeneralSets一对一引用(请不要问;))并且tblGeneralSets被多对一引用到tblContainers

所以我有两个程序来更新并选择已选择的任务:

DECLARE @SetIds AS TABLE(Id INT)    
-- Updating status
;WITH innerTable  AS 
(
    SELECT TOP 1 taskSets.* 
    FROM tblTasksSets taskSets WITH (XLOCK ROWLOCK) 
    INNER JOIN tblGeneralSets generalSets WITH(XLOCK ROWLOCK) ON generalSets.TaskSetId = taskSets.Id  
    WHERE generalSets.ContainerId = @ContainerId
      AND taskSets.ParameterSetStatusId = 1 --CREATED
) 
UPDATE innerTable 
SET ParameterSetStatusId = 2 -- STARTED
OUTPUT INSERTED.Id INTO @SetIds

-- Here are some unrelated updates on log history tables

-- And returning result
SELECT
    taskSets.*, containers.*
FROM 
    tblTasksSets taskSets
INNER JOIN 
    tblGeneralSets generalSets ON generalSets.TaskSetId = taskSets.Id
INNER JOIN 
    tblContainers containers ON containers.Id = generalSets.ContainerId
WHERE 
    taskSets.Id = (SELECT TOP 1 Id FROM @SetIds)

和第二个将任务标记为已完成:

UPDATE tblTasksSets 
SET 
....
WHERE Id = @Id

为什么我会陷入僵局?我只想要一个进程等待另一个进程完成更新。

  

System.Data.SqlClient.SqlException(0x80131904):事务(进程ID 53)在锁资源上与另一个进程死锁,并被选为死锁牺牲品。重新运行该交易。

在测试时,没有其他查询在此数据库上运行。每隔几秒钟就会有50个进程调用这两个存储过程

sp_lock shows something like this

Deadlock Graph

1 个答案:

答案 0 :(得分:1)

有一种强制方式可以序列化对资源的访问。使用sql server的内置锁定,您可以使用SP_GETAPPLOCK()对您的工作进行排队访问。一个例子是:

CREATE PROC MyCriticalWork(@MyParam INT)      
AS
    DECLARE @LockRequestResult INT = 0    
    DECLARE @MyTimeoutMiliseconds INT =5000--Wait only five seconds max then timeout

    BEGIN TRAN

    EXEC @LockRequestResult=SP_GETAPPLOCK 'MyCriticalWork','Exclusive','Transaction',@MyTimeoutMiliseconds
    IF(@LockRequestResult>=0)BEGIN

            /*
            DO YOUR CRITICAL READS AND WRITES HERE
            */

        COMMIT TRAN -- <--Releases the lock!
    END ELSE
        ROLLBACK TRAN