Sql 在自定义消息传递系统(队列)中尝试锁定记录时出现并发问题
我们正在构建自己的自定义消息传递系统,并且存在并发问题。规则如下: process EXE控制台应用程序锁定3条记录并返回它们 没有其他正在运行的进程我们有5个正在运行的EXE可以拾取其他进程已经获取的任何记录 这很简单,但我还是很困惑 执行锁定和查看的SQL存储过程摘要: 这背后的想法是,我们保留三条新记录,并在SELECT和UPDATE语句上使用行锁将其状态更改为“进行中”。因此,理论上,这些记录应该为一个进程锁定,以便其他进程无法更新甚至选择它们。有人能告诉我我做错了什么吗Sql 在自定义消息传递系统(队列)中尝试锁定记录时出现并发问题,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我们正在构建自己的自定义消息传递系统,并且存在并发问题。规则如下: process EXE控制台应用程序锁定3条记录并返回它们 没有其他正在运行的进程我们有5个正在运行的EXE可以拾取其他进程已经获取的任何记录 这很简单,但我还是很困惑 执行锁定和查看的SQL存储过程摘要: 这背后的想法是,我们保留三条新记录,并在SELECT和UPDATE语句上使用行锁将其状态更改为“进行中”。因此,理论上,这些记录应该为一个进程锁定,以便其他进程无法更新甚至选择它们。有人能告诉我我做错了什么吗 ALTER P
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
找到了!向@MaxVernon致敬 基本上是@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
那么你是否期待着选择。。。使用NOLOCK语句无法读取行锁定的行?您的问题还不清楚。为什么不使用SQL Server的内置队列机制Service Broker?除了我分配StatusIDInProgress变量的第一个选项外,所有的选择都带有ROWLOCK。。。我真的不在乎锁不锁。。。bAlso最后一个SELECT语句我也不太关心,它只是@ListOfIDs表变量中的SELECT和update Queues表中的update,它们都有ROWLOCK。我觉得您需要自动选择和更新行,这样其他进程就不会选择它们。也许这会有所帮助:ID所在的点一次只更新一个进程。我想你也许能把其中一个答案应用到你的特殊问题上。不完全是100%的直截了当,但可能足以让你走上正确的方向。