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

당신은이 경우에 더 좋을 수 ROWLOCK이 UPDLOCK은 READPAST 대기열로 테이블을 사용하는 데 사용할 수있는 직접 삭제를 실행하고 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

+0

이것은 내가 생각하는 가장 우아한 방법입니다. 고맙습니다! (btw : 귀하의 구문이 잘못되었습니다. 그것은 "DELETE TOP (1) ... WITH() ... OUTPUT ... WHERE"의 순서가되어야합니다. 또한 OUTPUT이 유효한 테이블을 생성 할 때 임시 테이블을 버릴 수도 있습니다. 결과 세트. – Krumelur

+0

@ Krumelur - READPAST는 행이 잠겨 있으면 무시하도록 지시합니다. 따라서이 코드를 동시에 실행하는 두 개의 연결이있는 경우 "첫 번째"행을 잠그고 반환하고 두 번째 행은 무시하고 select 두 번째 연결 - 그렇지 않으면 두 번째 연결은 "두 번째"행을 가져 오기 전에 잠금 (및 후속 삭제)이 발생할 때까지 대기합니다. "ORDER BY 절이 없으므로"첫 번째 및 두 번째 따옴표가 따옴표로 묶입니다. 쿼리. –

2

당신은

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"이고 정확히 3 가지 쿼리 힌트 (ROWLOCK, READPAST, UPDLOCK)가 필요한가요? 왜 DELETE 문을 변경 했습니까? 제가 한 일을 글로 쓰는 것이 더 우아한 방법일까요? – Krumelur

관련 문제