Я пытаюсь использовать TransactionScope с NHibernate для вызова нескольких методов в одной транзакции.Методы хранилища данных выглядят так:
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;
}
}
}</p>
<p>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 () и затем с новым значением.Как я могу добиться блокировки с этой моделью?