2009-09-26 3 views
7

멀티 세션 환경에서 특정 클라이언트 세션이 레코드를 얻었고 (이후 추가 업데이트를 위해 소유하고 있음을 나타 내기 위해) 테이블의 단일 레코드를 업데이트하려고합니다. 지금까지이있어 :원자 배타적 SQL 레코드 업데이트

create procedure AcquireRow(
    @itemNo int,   -- Item ID to acquire 
    @sessNo int,   -- Session ID 
    @res  char(1) out) -- Result 
as 
begin 
    -- Attempt to acquire the row 
    update Items 
    set 
     State = 'A',  -- 'A'=Acquired 
     SessionID = @sessNo 
    where ItemID = @itemNo 
     and State = 'N'; -- 'N'=Not acquired 

    -- Verify that the session actually acquired the row 
    set @res = 'T';  -- 'T'=Success 
    if @@rowcount = 0 
    set @res = 'F';  -- 'F'=Failure 
end; 

아웃 된 변수 @state이 프로 시저가 성공적으로 행을 구입 한 경우 'T'로 설정, 그렇지 않으면 실패를 나타내는 'F'로 설정합니다.

내 질문 : 여러 세션에서 AcquireRow()을 동시에 호출하면 하나의 세션 만 성공적으로 (업데이트) 행을 얻을 수 있도록 원자 적으로 작동하도록 보장됩니까? 아니면 이것을하는 더 좋은 방법이 있습니까? 명시 적으로 rowlock이 필요합니까?

는 개정 : 레무스의 답변에 따라
, 나는 이렇게 코드를 재 배열 :

set @res = 'F'; 
update ...; 
if @@rowcount > 0 
    set @res = 'T'; 

output 절을 사용하거나 update 내에서 변수에 결과 행의 ItemID는 신중한 것 할당.

+0

아주 비슷한 질문이 있으므로 의문이 들지만 찾지 못했습니다 .... –

+0

이 글은 비슷하지만 마음에두고있는 것은 아닙니다 : http://stackoverflow.com/questions/574549/ 효율적인 트랜잭션 레코드 잠금 –

답변

9

@@ROWCOUNT 악명이 높습니다. 예를 들어, 귀하의 경우. MSDN에서 : 만들

문 간단한 할당은 항상 어떤 행이 클라이언트로 전송되지 않습니다 1로 @@ROWCOUNT 값을 설정합니다. 이러한 진술 의 예는 다음과 같습니다 SET @local_variable ...

은 즉시 UPDATE 후 @@ ROWCOUNT를 확인해야 정확합니다. ROWLOCK을 사용하는 것이 더 안전하지만 필수는 아닙니다. 옵티마이 저가 페이지 잠금을 사용하기로 결정하더라도 '획득'의미론은 정확합니다.

아마 즉 UPDATEOUTPUT 절을 사용하는 또 다른 접근 방식을 선호 : 그것은 알 수없는 항목 Id의 취득을 허용으로

declare @updated table (ItemId int); 

update Items 
set ... 
output inserted.ItemId 
into @updated (ItemId) 
where ... 

이 제도가보다 유연도 이상의 오류 방지 및입니다 : ID는 인수 @updated 테이블 변수에 저장되며 호출자에게 반환 될 수 있습니다.

일반적으로 실제, 커밋 된 'acquire'에 대한 업데이트를 사용하면 실제로 취득한 행과 방금 포기 된 행을 알 수 없으므로 문제가 생겨납니다 (클라이언트가 연결이 끊어 지거나 크래시가 발생하지 않고 '획득'이 해제 됨). ').

+0

감사합니다. @@ rowcount라는 숨겨진 위험에 대해 알지 못했습니다. 이전 버전의 원시 코드에서는'update' 전에'@ res'를 설정 했으므로 그 문제는 없었습니다. 영향받은 행의 ID를 캡처하기 위해'output' 또는'set @updateID = ItemID = @ itemNo' 사용을 고려했지만 확실치 않았습니다. 정보 주셔서 감사합니다. –

3

SQL Server의 UPDATE 문은 데이터베이스 엔진이 업데이트가 필요한 행을 읽는 동안 업데이트 잠금을 가져 오며, 쓰기가 발생할 때 독점적 잠금으로 변환됩니다.

독점 잠금이 행에있을 때 읽기 트랜잭션이 READ UNCOMMITTED 격리 상태가 아니거나 NOLOCK 힌트가 사용되지 않는 한 모든 다른 트랜잭션은 읽기 및 쓰기가 차단됩니다.

그렇습니다. 귀하의 UPDATE 문은 자동 자동 트랜잭션이기 때문에 여러 세션에서 동시에 호출하는 것이 좋습니다. 어떤 이유로 든 여러 구문으로 나눌 수 있다면 SP에 명시 적으로 트랜잭션을 생성해야합니다.

Remus '@@ ROWCOUNT에 대한 의견 및 "acquire"의 일반적인 사용법은 매우 충실한 조언입니다.

+0

멋진 업데이트 - MSDN 또는 이와 비슷한 내용이 있습니까? –

관련 문제