我们正在构建自己的自定义消息传递系统,并且存在并发问题。以下是规则:
进程(EXE)控制台应用程序锁定3条记录并将其返回
没有其他进程正在运行(我们有5个EXE正在运行)可以选择其他进程已经采取的任何记录。
那很简单,但是,我很困惑。
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
答案 0 :(得分:0)
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