2010-08-20 5 views
2

하나의 트랜잭션에서 여러 메소드를 호출하기 위해 NHibernate와 함께 TransactionScope를 사용하려고합니다. 데이터 저장소 방법은 다음과 같습니다 : 나는 몇 가지 단위 테스트와 일부 콘솔 응용 프로그램을 만들 수 있도록NHibernate, TransactionScope and locking

 
public virtual void Save(T dataObject) 
{ 
    try 
    { 
     using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead })) 
     { 
      this.session.SaveOrUpdate(dataObject); 
      scope.Complete(); 
     } 
    } 
    catch (Exception ex) 
    { 
     bool rethrow = ExceptionPolicy.HandleException(ex, "Data Layer Policy"); 
     if (rethrow) 
     { 
      throw; 
     } 
    } 
}

public T GetByNumber(string documentNumber) { T document = null; try { using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead })) { document = this.Session.CreateCriteria(typeof(T)) .Add(Restrictions.Eq("Number", documentNumber)) .UniqueResult(); scope.Complete(); } } catch (Exception ex) { bool rethrow = ExceptionPolicy.HandleException(ex, "Data Layer Policy"); if (rethrow) { throw; } } return document; }

내가 거래를 행/테이블 잠금을 테스트하고 싶었다. 데이터베이스에서 같은 행을 읽고

 
const string DocumentNumber = "386774321"; 
Random randomGenerator = new Random(); 
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead })) 
{ 
    using (BillingDocumentRepository billingDocumentRepository = new BillingDocumentRepository()) 
    { 
     BillingOrderData orderData = billingDocumentRepository.GetByNumber(DocumentNumber); 
     orderData.Notes = randomGenerator.Next().ToString(); 
     Console.WriteLine(string.Format("SECOND: {0}: Updated notes to {1}.", DateTime.Now.ToString("HH:mm:ss.fffff"), orderData.Notes)); 
     Console.WriteLine(string.Format("SECOND: {0}: Updating order.", DateTime.Now.ToString("HH:mm:ss.fffff"))); 
     Console.WriteLine(string.Format("SECOND: {0}: Going to sleep for 10000ms.", DateTime.Now.ToString("HH:mm:ss.fffff"))); 
     Sleep(10000); // My custom sleep method because I didn't want to use Thread.Sleep for simulating long transaction 
     billingDocumentRepository.Save(orderData); 
    } 
    Console.WriteLine(string.Format("SECOND: {0}: Going to sleep for 10000ms.", DateTime.Now.ToString("HH:mm:ss.fffff"))); 
    Sleep(10000); 
    Console.WriteLine(string.Format("SECOND: {0}: Completing transaction.", DateTime.Now.ToString("HH:mm:ss.fffff"))); 
    scope.Complete(); 
} 

응용 프로그램 :

 
while (true) 
{ 
    using (BillingDocumentRepository repository = new BillingDocumentRepository()) 
    { 
     Console.WriteLine(string.Format("MAIN: {0}: Getting document.", DateTime.Now.ToString("HH:mm:ss.fffff"))); 
     BillingOrderData billingOrderData = repository.GetByNumber("386774321"); 
     Console.WriteLine(string.Format("MAIN: {0}: Got order with notes {1}.", DateTime.Now.ToString("HH:mm:ss.fffff"), billingOrderData.Notes)); 
     Sleep(1000); 
    } 
} 

문제가 (행을 업데이트) 첫 번째 트랜잭션은 '아무튼 것입니다 업데이트가 수행

응용 프로그램 : 다음은이 콘솔 응용 프로그램의 코드는 언제라도 읽을 수있는 행 잠금. 두 번째 응용 프로그램은 scope.Complete() 이전의 값으로 항상 그 행을 읽고 그 이후의 새로운 값보다 깁니다. 이 모델로 어떻게 잠금을 얻을 수 있습니까?

답변

0

session.Lock(object) 방법이 있습니다.

session.Save(object)를 호출하면 NHibernate는 플러시 될 때까지 데이터베이스에서 아무 작업도 수행하지 않습니다.

플러싱는

  • 트랜잭션을 커밋합니다 (경우 높이를 명시 적으로 호출 할 때 (가져 오기 및로드 제외) 쿼리 전에

    • (보통의 autoflush입니다 플러시 모드에 따라 다름) 완료 연결은 NH 생각에 의해 만들어진다)

    세션이 플러시되면 실제 업데이트, 삽입 및 삭제 작업이 데이터베이스에서 수행되고 잠금이 설정됩니다.

    SQL Server에서 잠금이 설정된 경우 읽기 트랜잭션은 업데이트 트랜잭션이 커밋 될 때까지 대기합니다. 커밋되면 커밋 된 값을 읽습니다 ("커밋 된 읽기"격리 상태 일 때).

  • +1

    나는이 세션을 가지고 : session.FlushMode = FlushMode.Commit; 실제 업데이트가 커밋시 수행된다는 것을 알고 있지만 데이터베이스 쿼리가 실행될 때만 잠금이 수행되는 경우 TransactionScope 및 격리 수준의 요점은 무엇입니까? 다음은 격리 수준에 대한 SQL Server 설명서 링크입니다. http://msdn.microsoft.com/en-us/library/aa259216(SQL.80).aspx 에 따르면 내부에서 수행되는 모든 SELECT Repeatable Read 격리 수준의 트랜잭션은 필자의 예제에서는 대소 문자가 아닌 행에 잠금을 설정해야합니다. – IvanQ

    +0

    중첩 된 트랜잭션에 문제가있을 수도 있습니다. 나는이 트랜잭션 범위를 사용하지 않는다. 나는 실제로 내가 무슨 일을 하는지를 스스로 알고있다. –

    +0

    NHibernate 세션과 트랜잭션을 추상화 할 곳을 쓰고 싶다. 그러나 NHibernate 트랜잭션을 사용하는 몇 가지 테스트를 작성했다. 결과는 같습니다. 잠금은 데이터가 기록 될 때만 획득됩니다. – IvanQ