2011-03-07 71 views
1

在SQL位下,我想获取和删除匹配特定条件的表的下一行。但是,我想阻止执行相同位SQL的其他服务返回同一行。我正在考虑交易或行锁,但无法看到任何一个人会如何帮助我。在SQL Server上读取锁定行?

DECLARE @tblTempRow TABLE(intUserID int, intBlobID int) 

-- Get the next match and remember in temp table. I want to prevent that other processes return the same row. 
INSERT INTO @tblTempRow(intUserID, intBlobID) 
SELECT TOP 1 intUserID, intBlobID FROM Schedule WHERE intScheduleType = @intScheduleType 

-- Delete if requested. 
IF(@intDeleteAfterGet = 1) 
BEGIN 
     DELETE FROM 
     Schedule 
    WHERE 
     intUserID = (SELECT intUserID FROM @tblTempRow) 
     AND intBlobID = (SELECT intBlobID FROM @tblTempRow) 
       AND intScheduleType = @intScheduleType 
END 

-- Return the temp table. 
SELECT intUserID, @intScheduleType, intBlobID FROM @tblTempRow 

回答

2

你可能是在这种情况下,更好地直接发出删除,并使用OUTPUT clause填充表格。这应该自动管理你的锁。 TODO:处理没有匹配的行,但你已经有这个问题。

DECLARE @tblTempRow TABLE(intUserID int, intBlobID int) 

IF(@intDeleteAfterGet = 1) 
begin 
    DELETE TOP 1 FROM Schedule WITH (READPAST) WHERE intScheduleType = @intScheduleType 
    OUTPUT deleted.intUserID,deleted.intBlobID INTO @tblTempRow 
end 
else 
begin 
    INSERT INTO @tblTempRow(intUserID, intBlobID) 
    SELECT TOP 1 intUserID, intBlobID FROM Schedule WHERE intScheduleType = @intScheduleType 
end 

-- Return the temp table. 
SELECT intUserID, @intScheduleType, intBlobID FROM @tblTempRow 
+0

什么是READPAST查询提示? – Krumelur 2011-03-07 14:00:38

+0

这是我认为最优雅的方式。谢谢! (顺便说一句:你的语法错误,它需要按照“DELETE TOP(1)... WITH()... OUTPUT ... WHERE”的顺序排列,因为OUTPUT会生成一个有效的结果集 – Krumelur 2011-03-07 14:14:40

+0

@Krumelur - READPAST说如果一行被锁定,就忽略它,所以如果你有两个连接同时运行这个代码,一个会锁定并返回“第一个”行,第二个会忽略它,然后选择第二行 - 否则,第二个连接将等待锁定(以及之后的删除),然后才能得到“第二个”行。“引用中的第一个”和“第二个”是因为这里没有ORDER BY子句查询 – 2011-03-07 14:43:14

2

您可以使用ROWLOCK,UPDLOCK,READPAST用一个表作为队列(这是你在做什么)

SQL Server Process Queue Race Condition

DECLARE @tblTempRow TABLE(intUserID int, intBlobID int) 

--no rollback needed now. will automatically roll back 
SET XACT_ABORT ON 

-- to span select and delete 
BEGIN TRANSACTION 

-- Get the next match and remember in temp table. I want to prevent that other processes return the same row. 
INSERT INTO @tblTempRow(intUserID, intBlobID) 
SELECT TOP 1 intUserID, intBlobID 
--for hints, see link above 
FROM Schedule WITH (ROWLOCK, READPAST, UPDLOCK) 
WHERE intScheduleType = @intScheduleType 

-- Delete if requested. 
IF(@intDeleteAfterGet = 1) 
BEGIN 
     DELETE 
     Schedule S 
    WHERE --yes, more elegant 
     EXISTS (SELECT * FROM 
      @tblTempRow T 
      WHERE 
       S.intUserID = T.intUserID AND 
       S.intBlobID = T.intBlobID) 
     AND 
     S.intScheduleType = @intScheduleType 
END 
COMMIT TRANSACTION 

-- Return the temp table. 
SELECT intUserID, @intScheduleType, intBlobID FROM @tblTempRow 
+0

谢谢。你能稍微评论你的改变吗? “XACT_ABORT”是什么以及为什么这三个查询提示(ROWLOCK,READPAST,UPDLOCK)?你为什么改变DELETE语句?这只是一种更优雅的写作方式吗? – Krumelur 2011-03-07 13:57:47