2010-11-23 3 views
1

Последующий отчет this other question.NHibernate - пессимистическая блокировка не работает

Я пытаюсь реализовать пессимистическую блокировку для проблемы параллелизма, как я описал в вопросе выше (пожалуйста, не стесняйтесь добавлять к нему). Но это не работает для меня.

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

Вот код. Конечно, это не производственный код, но тестовый код или нет, он все равно должен работать, правильно?

for (int i = 0; i < 500; i++) 
{ 
    var tx = this.userRepo.Session.BeginTransaction(); 
    var user = this.userRepo.GetById(42); 
    user.Counter++; 
    userRepo.Save(user); 
    tx.Commit(); 
} 

Метод GetById использует LockMode.Upgrade:

public T GetById(int id) 
{ 
    T obj = Session.Get<T>(id, LockMode.Upgrade); 
    return obj; 
} 

Теперь, используя NHProfiler я вижу следующий SQL заявление:

SELECT Id FROM 'User' WHERE Id = 42 for update

, но результатом является значение около , так что примерно половина обновлений потеряна из-за параллелизма. Что я делаю не так? Я отключил кеш второго уровня в этом тесте. Использую ли я неправильный режим блокировки? Должен ли я указывать уровень изоляции? Что-нибудь еще? Заранее спасибо.

EDIT: FluentNhibernate конфигурации:

Fluently.Configure() 
.Database(MySQLConfiguration.Standard.ConnectionString(connectionstring)) 
.Mappings(m => assemblyTypes.Select(t => t.Assembly).ToList().ForEach(a => m.FluentMappings.AddFromAssembly(a))) 
.ExposeConfiguration(c => c.Properties.Add("hbm2ddl.keywords", "none")); 
+0

Можете ли вы опубликовать свой конфигурационный код Nhibernate? – UpTheCreek 2010-11-23 08:41:23

+0

@UpTheCreek: используя FluentNH, не уверен, что вы хотите видеть, но я включил его. – Razzie 2010-11-23 09:12:32

ответ

0

Для LockMode.Upgrade работать, все операции должны быть заключены в сделке, потому, что LockMode.Upgrade делает зафиксировалась в текущей транзакции.

Ваша проблема, скорее всего, связана с заявлениями, не заключенными в транзакцию.

Оптимистическая блокировка не применяется к одному оператору, а относится к нескольким транзакциям, которые отделены друг от друга. Пример:

  1. Начните сделку;

  2. Получить данные от Id = 42;

  3. Завершить сделку.

После этого, за пределами сделки, увеличение Counter.

После этого:

  1. начать транзакцию;

  2. Получить данные от Id = 42;

  3. Проверьте, не был ли счетчик неизменным от значения, полученного в первой транзакции;

    a. Если он не изменился, обновите счетчик с увеличенным значением;

    b. Если он изменился, отредактируйте измененное значение.

  4. Завершить сделку.

Оптимистическая блокировка означает, что «надежда» Counter не изменилась между двумя транзакциями и обрабатывает случай, когда она изменилась. С пессимистической блокировкой вы гарантируете, что все изменения будут выполнены в рамках одной транзакции со всеми заблокированными записями.

B.t.w: механизм проверки (независимо от того, изменился ли Counter), может быть автоматически обработан NHibernate.