하나의 트랜잭션에서 여러 메소드를 호출하기 위해 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() 이전의 값으로 항상 그 행을 읽고 그 이후의 새로운 값보다 깁니다. 이 모델로 어떻게 잠금을 얻을 수 있습니까?
나는이 세션을 가지고 : session.FlushMode = FlushMode.Commit; 실제 업데이트가 커밋시 수행된다는 것을 알고 있지만 데이터베이스 쿼리가 실행될 때만 잠금이 수행되는 경우 TransactionScope 및 격리 수준의 요점은 무엇입니까? 다음은 격리 수준에 대한 SQL Server 설명서 링크입니다. http://msdn.microsoft.com/en-us/library/aa259216(SQL.80).aspx 에 따르면 내부에서 수행되는 모든 SELECT Repeatable Read 격리 수준의 트랜잭션은 필자의 예제에서는 대소 문자가 아닌 행에 잠금을 설정해야합니다. – IvanQ
중첩 된 트랜잭션에 문제가있을 수도 있습니다. 나는이 트랜잭션 범위를 사용하지 않는다. 나는 실제로 내가 무슨 일을 하는지를 스스로 알고있다. –
NHibernate 세션과 트랜잭션을 추상화 할 곳을 쓰고 싶다. 그러나 NHibernate 트랜잭션을 사용하는 몇 가지 테스트를 작성했다. 결과는 같습니다. 잠금은 데이터가 기록 될 때만 획득됩니다. – IvanQ