开发者

Lock row for reading on SQL Server?

In the bit of SQL down I would like to get and delete the next row of a table matching specific criteria. However, I want to prevent other services executing the same bit of SQL to return the same row. I was thinking about transactions or row locks but can't see how either one would help me.

DECLARE @tblTempRow TABLE(intUserID int, intBlobID int)

-- Get the next match and remember in tem开发者_StackOverflow社区p 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


You may be better in this case to issue a delete directly, and use the OUTPUT clause to populate your table. That should manage the locks for you automatically. TODO: deal with no matching rows, but you have that issue already.

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


You can use ROWLOCK, UPDLOCK, READPAST to use a table as a queue (which is what you are doing)

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜