Я пытаюсь использовать TransactionScope с NHibernate, чтобы вызвать несколько методов в одной транзакции. Методы хранилища данных, как это:NHibernate, TransactionScope и блокировка
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);
}
}
Проблема заключается в том, что первая транзакция (которая обновляет строку) Безразлично» t блокировка строки для чтения в любой момент. Второе приложение читает эту строку все время со старым значением перед областью scope.Complete() и после этого новое значение. Как я могу добиться блокировки с помощью этой модели?
У меня есть это для сеансов: session.FlushMode = FlushMode.Commit; Я знаю, что фактическое обновление выполняется при фиксации, но какова точка TransactionScope и уровень изоляции, если блокировка выполняется только при выполнении запросов к базе данных? Ссылка на документацию SQL Server об уровнях изоляции: http://msdn.microsoft.com/en-us/library/aa259216(SQL.80).aspx В соответствии с этим каждый SELECT, который выполняется внутри транзакция с уровнем повторного считывания Чтение должно содержать блокировку строк (строк), которая не является примером в моем примере. – IvanQ
Я также могу быть проблемой с вложенными транзакциями. Я не использую эту область транзакций - я написал свое собственное, где я знаю, что на самом деле происходит ... –
Я подумываю написать свое собственное, где я бы отменил сеанс и транзакцию NHibernate, но теперь я написал несколько тестов, которые используют транзакцию NHibernate и результат тот же. Замки приобретаются только при записи данных. – IvanQ