2017-12-06 3 views
0

몇 가지 요청을 거의 동시에받는 Webservice가 있습니다.엔티티 프레임 워크에서 교착 상태가 발생했습니다.

두 개의 요청 트랜잭션이 교착 상태가 발생하여 재실행을 롤백해야합니다.

 using (var context = new DbContext()) 
     using (var dbContextTransaction = context.Database.BeginTransaction(IsolationLevel.Serializable)) 
     { 
       var subscription = context.Subscriptions.FirstOrDefault(x => x.Provider == provider); 
       if (subscription == null) 
       { 
        */Insert*/ 
       } 
       else 
       { 
        /*Update*/ 
       } 
       context.SaveInTransaction(null); 
       dbContextTransaction.Commit(); 
       } 

저는 두 요청 모두 거래를 입력하고 구독 표를 읽음을 이해합니다. 커밋 준비가 완료되면 다른 트랜잭션 (IsolationLevel.Serializable)에서 읽은 데이터 범위에 값을 삽입 할 수 없기 때문에 교착 상태가됩니다.

TransactionLevel Serialize를 만들지 않으면 요청 중 하나가 공급자 열의 고유 제약 조건을 충족하지 못하고 Rollbacked가 발생합니다.

교착 상태를 방지하려면 어떻게해야합니까? 내가 TransactionLevel Serializeable을하지 않으면

+0

당신이 사용할 수있는'lock' https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/ :

당신처럼 DbContext 뭔가에 메서드를 추가 할 수 있습니다 keywords/lock-statement – Hackerman

+2

고유 한 위반을 나타내는 예외를 catch하고 재 시도하거나 원시 작업을 수행하기 위해 raw SQL을 사용하여 하나의 원자 작업에서 "upsert"(SQL 서버의 해당 작업이 MERGE 임)를 수행하십시오. 나는 EF에서 그것을 다루는 다른 방법을 알지 못한다. – Evk

답변

2

는 요청 중 하나는 공급자 컬럼의 고유 제한 조건을 충족 실패하고 롤백 할을 가져옵니다.

당신은 할 수 있습니다

1)은 PK 위반/교착 상태를 처리하고 기존 행을 업데이트를 진행합니다. READ COMMITTED를 사용하고 실패한 세션이 업데이트를 진행할 수 있으므로 PK 위반을 처리해야합니다. SERIALIZABLE을 사용하면 INSERT 또는 UPDATE에서 교착 상태가 발생할 수 있습니다.

2) 잠금 힌트가있는 원시 SQL을 사용하여 한 세션이 다른 세션을 대기하게하십시오.

올바른 잠금 힌트는 (UPDLOCK, SERIALIZABLE)입니다. 그리고 MERGE를 사용한다면 여전히 잠금 힌트는 이어야합니다.. https://blogs.msdn.microsoft.com/dbrowne/2013/02/25/why-is-tsql-merge-failing-with-a-primary-key-violation-isnt-it-atomic/

3) 트랜잭션 시작시 sp_getapplock으로 전화하여 단 하나의 세션에만 잠금이 설정되도록하십시오. CLR 잠금은 응용 프로그램의 단일 인스턴스가있는 경우에만 작동합니다. 클라이언트/서버 응용 프로그램 또는 웹 팜의 경우 CLR 잠금이 작동하지 않습니다.

public void GetAppLock(string lockName) 
{ 
    this.Database.ExecuteSqlCommand("exec sp_getapplock @name, 'exclusive'", new System.Data.SqlClient.SqlParameter("@name",lockName)); 
} 
+0

SERIALIZABLE만으로 충분하지 않습니까? 왜 또한 updlock이 필요합니까? – Evk

+0

SERIALIZABLE은 다른 경우 S 잠금을 사용하므로 SELECT에 UPDLOCK이 필요합니다. MERGE (또는 UPDATE)의 경우 SERIALIZABLE로 충분합니다. 이미 읽을 때 U 자물쇠를 사용하기 때문에 빈 키 범위에 대해 범위 잠금을 추가하면됩니다. –

+0

아, 나는 병합에 힌트가 구체적으로 필요하다는 것을 의미하지만 – Evk

관련 문제