2010-05-20 2 views
1

필자는 본질적으로 ETL 작업을 수행하는 linq-to-sql 프로그램을 작성했으며 병렬 처리가 성능을 향상시키는 곳이 많다는 것을 알고 있습니다. 그러나, 두 스레드가 다음 작업 (psuedo 코드)을 수행 할 때 uniquness 제약 조건 위반을 방지하는 데 관심이 있습니다. 일반적다음 삽입 삽입하지 않는 트랜잭션에 어떤 격리 수준을 사용해야합니까?

Record CreateRecord(string recordText) 
{ 
    using (MyDataContext database = GetDatabase()) 
    { 
     Record existingRecord = database.MyTable.FirstOrDefault(record.KeyPredicate()); 
     if(existingRecord == null) 
     { 
      existingRecord = CreateRecord(recordText); 
      database.MyTable.InsertOnSubmit(existingRecord); 
     } 

     database.SubmitChanges(); 
     return existingRecord; 
    } 
} 

이 코드는 기록이 존재하지 않는 경우 INSERT 문장 뒤에 기록 실존 테스트하는 SELECT 명령문을 실행한다. 암시 적 트랜잭션에 의해 캡슐화됩니다.

두 스레드가 recordText의 동일한 인스턴스에 대해이 코드를 실행하면 두 레코드가 동일한 레코드를 만들려고 시도하면서 레코드가 존재하지 않는다고 동시에 판단하지 못하도록하고 싶습니다. 격리 수준과 명시 적 트랜잭션은 잘 작동 할 것입니다. 제외 수준을 사용해야하는지 확신 할 수 없다면 (Serializable) 작동해야하지만 너무 엄격한 것 같습니다. 더 나은 선택이 있습니까?

답변

1

이러한 상황을 피하기 위해 아래와 비슷한 SQL을 사용합니다. UPDLOCK은 트랜잭션이 완료되고 HOLDLOCKSERIALIZABLE과 같을 때까지 갱신 잠금을 취하고 보유하도록 지정합니다. SERIALIZABLE은 트랜잭션이 완료되었는지 여부에 관계없이 필요한 테이블이나 데이터 페이지가 더 이상 필요하지 않은 즉시 공유 잠금을 해제하는 대신 트랜잭션이 완료 될 때까지 공유 잠금을 더 제한적으로 유지함으로써 공유 잠금을보다 제한적으로 만듭니다. 검색은 SERIALIZABLE 격리 수준에서 실행중인 트랜잭션과 동일한 의미로 수행됩니다. HOLDLOCK은 지정된 테이블 또는 뷰에만 적용되며 사용되는 명령문에 정의 된 트랜잭션 기간 동안 만 적용됩니다. 옵션에 포함 된 SELECT 문에 HOLDLOCK을 사용할 수 없습니다.

declare @LocationID   int 
declare @LocationName  nvarchar (50) 

/* fill in LocationID and LocationName appropriately */ 

INSERT dbo.Location 
(LocationID, LocationName) 
SELECT @LocationID, @LocationName 
WHERE NOT EXISTS (
    SELECT L.* 
    FROM dbo.Location L WITH (UPDLOCK, HOLDLOCK) 
    WHERE L.LocationID = @LocationID) 

this question에 대한 답에 따르면, 직렬화 갈 방법이 될 것으로 보인다.