2011-03-07 118 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