2011-09-14 6 views
1

와의 라인을 따라 뭔가 않는 응용 프로그램 고려 "삽입은하지 않을 경우 존재"NHibernate에

var user = session.QueryOver<User>().Where(x => x.Name==name).SingleOrDefault(); 

if (user == null) 
{ 
    user = new User(name); 
    session.Save(user); 
} 

비즈니스 규칙은 사용자의 이름은 고유해야한다는, 그리고이은에 UNIQUE INDEX에 의해 백업됩니다 데이터 베이스. 위의 코드는 두 명의 사용자가 같은 이름을 사용하여 동시에 등록하려고 시도 할 때까지 잘 작동합니다. 둘 다 user == null이되고 새 번호는 User입니다. 커밋 할 첫 번째 명령은 성공하고 두 번째 명령은 데이터베이스에서 발생한 예외와 함께 실패합니다.

이러한 경쟁 조건을 피하는 한 가지 방법은 lock { } 블록에 중요한 코드를 래핑하는 것이지만 응용 프로그램의 여러 인스턴스가 동일한 데이터베이스에 대해 작동 할 때 도움이되지 않습니다. 자, RDBS (이 경우 MS SQL)의 잠금 메커니즘을 사용할 수만 있다면 ...

이것은 내가 갇혀있는 곳입니다. NHibernate 문서에서 읽을 수있는 것부터, 명시 적 잠금을 요청하는 내 QueryOver() 체인에 힌트를 추가하여 해결할 수 있습니다. 나는 아직 실제 행이 없기 때문에 테이블 잠금이어야한다. 이것이 가능한가? How

또는 트랜잭션의 격리 수준을 높이고 필요한 잠금을 자동으로 얻을 수 있습니까? 동일한 작업 단위 내에서 다른 (문제가 아닌) 쿼리가 수행되었다는 것을 고려할 때, 나는 이러한 종류의 변경이 많은 차단/대기를 유발할 수 있다고 생각합니다. 그래?

+0

이 질문에 대한 복제본을 찾은 것일 수 있습니다 : [NHibernate transaction and race condition] (0120-13992/nhibernate-transaction-and-race-condition) –

답변

0

저장할 때와 동일한 NHibernate 세션을 통해 쿼리를 실행해야합니다. 이렇게하면 데이터베이스의 잠금 메커니즘을 자동으로 활용하여 동일한 트랜잭션을 사용할 수 있습니다.

그런데 항상은 트랜잭션이 실패 할 준비가되어야하며 코드는이 케이스를 정상적으로 처리해야한다고 말했습니다. 직렬화 된 블록 및 잠금을 사용하면 코드가 복잡해 지지만 데이터베이스 수준에서 오류가 발생할 가능성을 없앨 수는 없기 때문에 이러한 복잡성을 거의 얻지 못할 수도 있습니다.

+0

두 쿼리가에서 실행됩니다. 동일한 트랜잭션이 이미 있으며 예외 로그에서 고유 인덱스 위반이 발생합니다. 자동 잠금이 작동하려면 트랜잭션의 격리 수준을 높여야합니까? –

2

격리 수준을 직렬 가능으로 늘리십시오. 그러면 'where'절을 포함하여 전체 쿼리에서 읽기 및 쓰기 잠금이 모두 획득됩니다.