尝试锁定自定义消息传递系统(队列)中的记录时遇到并发问题

时间:2015-01-02 21:27:07

标签: sql sql-server sql-server-2008

我们正在构建自己的自定义消息传递系统,并且存在并发问题。以下是规则:

  1. 进程(EXE)控制台应用程序锁定3条记录并将其返回

  2. 没有其他进程正在运行(我们有5个EXE正在运行)可以选择其他进程已经采取的任何记录。

  3. 那很简单,但是,我很困惑。

    SQL SPROC执行" Lock And Peek":

    的摘要

    这背后的想法是我们保留三个" NEW"记录并将其状态更改为" IN PROGRESS"在SELECT和UPDATE语句中使用ROWLOCK。因此理论上,这些记录应该锁定一个过程,以便其他过程不能更新甚至选择它们。有人可以告诉我,我做错了吗?

    ALTER PROCEDURE [dbo].[LockAndPeek] 
        @Count INT,
        @QueueTypeId INT
    AS
    BEGIN
        SET NOCOUNT ON;
    
        DECLARE @ListofIDs TABLE(ID INT);
        DECLARE @StatusIDInProgress INT
    
        SELECT @StatusIDInProgress = ID FROM QueueStatuses (NOLOCK)
        WHERE Name = 'In Progress'
    
        INSERT INTO @ListofIDs
        (ID)
        SELECT TOP (@Count) Q.ID 
        FROM
            Queues Q (ROWLOCK) INNER JOIN
            QueueStatuses QS (ROWLOCK) ON Q.StatusID = QS.ID
        WHERE
            QS.Name IN ('New', 'Errored') AND
            Q.TypeID = @QueueTypeID AND
            Q.AvailableTime IS NOT NULL AND
            Q.AvailableTime <= GETUTCDATE()
        ORDER BY Q.ID
    
        UPDATE Q WITH (ROWLOCK)
        SET 
            STATUSID = @StatusIDInProgress,
            PROCESSED = GETUTCDATE()
        FROM
            Queues Q (ROWLOCK) INNER JOIN
            QueueStatuses QS (ROWLOCK) ON Q.StatusID = QS.ID INNER JOIN
            @ListofIDs LI ON Q.ID = LI.ID
        WHERE
            QS.Name IN ('New', 'Errored')
    
        SELECT  Q.ID, 
                Q.AvailableTime,
                Q.NumberOfTries,
                Q.Created,
                Q.Processed,
                Q.ErrorData,
                QT.ID QueueTypeID,
                QT.Name QueueTypeName,
                QS.ID QueueStatusID,
                QS.Name QueueStatusName,
                Q.Message
        FROM 
            Queues Q (NOLOCK) INNER JOIN
            QueueStatuses QS (NOLOCK) ON Q.StatusID = QS.ID INNER JOIN
            QueueTypes QT (NOLOCK) ON Q.TypeId = QT.ID INNER JOIN
            @ListofIDs LI ON Q.ID = LI.ID
    
    END
    

1 个答案:

答案 0 :(得分:0)

发现它! @MaxVernon的大热门!

http://rusanu.com/2010/03/26/using-tables-as-queues/基本上是@MaxVernon作为评论发布的变体。我的查询看起来像这样,比以前简单得多:

ALTER PROCEDURE [dbo].[LockAndPeek] 
    @Count INT,
    @QueueTypeId INT
AS
BEGIN

SET XACT_ABORT ON; -- blow up the whole tran on any errors
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRAN

UPDATE Q
SET 
    StatusID = 2, -- In Progress
    Processed = GETUTCDATE()
OUTPUT Inserted.*
FROM (
    SELECT TOP (@Count) * 
    FROM
        Queues WITH (READPAST, ROWLOCK)
    WHERE
        StatusID = 1 AND -- New 
        TypeID = @QueueTypeID AND
        AvailableTime IS NOT NULL AND
        AvailableTime <= GETUTCDATE()
   ORDER BY ID
) Q;

COMMIT TRAN;

END