2010-08-20 3 views
2

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

ответ

0

Существует метод session.Lock(object).

Когда вы вызываете session.Save(object), NHibernate ничего не делает в базе данных, пока не покраснеть.

Промывка осуществляется (в зависимости от режима смыва, который обычно AutoFlush)

  • перед тем запросов (кроме Досталось и нагрузки)
  • при вызове вровень явно
  • при совершении сделки (если соединение создается NH, я думаю)

Когда сеанс размывается, в базе данных выполняются фактические операции по обновлению, вставке и удалению, а блокировки установлены.

В SQL Server, когда блокировка установлена, транзакция чтения ожидает фиксации транзакции обновления. Когда он совершает ошибку, он считывает зафиксированные значения (когда вы находитесь в изоляции «Read Committed»).

+1

У меня есть это для сеансов: session.FlushMode = FlushMode.Commit; Я знаю, что фактическое обновление выполняется при фиксации, но какова точка TransactionScope и уровень изоляции, если блокировка выполняется только при выполнении запросов к базе данных? Ссылка на документацию SQL Server об уровнях изоляции: http://msdn.microsoft.com/en-us/library/aa259216(SQL.80).aspx В соответствии с этим каждый SELECT, который выполняется внутри транзакция с уровнем повторного считывания Чтение должно содержать блокировку строк (строк), которая не является примером в моем примере. – IvanQ

+0

Я также могу быть проблемой с вложенными транзакциями. Я не использую эту область транзакций - я написал свое собственное, где я знаю, что на самом деле происходит ... –

+0

Я подумываю написать свое собственное, где я бы отменил сеанс и транзакцию NHibernate, но теперь я написал несколько тестов, которые используют транзакцию NHibernate и результат тот же. Замки приобретаются только при записи данных. – IvanQ

Смежные вопросы