锁定行在SQL Server上读取?

时间:2011-03-07 13:46:16

标签: sql sql-server sql-server-2005

在SQL中,我希望得到并删除符合特定条件的表的下一行。但是,我想阻止执行相同SQL的其他服务返回同一行。我在考虑交易或行锁,但看不出任何人会帮助我。

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 个答案:

答案 0 :(得分: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

答案 1 :(得分: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