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
но в результате получается значение около 530, то есть около половины обновлений теряется из-за параллелизма. Что я делаю неправильно? Я отключил кэш второго уровня в этом тесте. Я использую неправильный режим блокировки? Должен ли я указать уровень изоляции? Что-нибудь еще? Заранее спасибо.
РЕДАКТИРОВАТЬ: FluentNhibernate config:
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"));
1 ответ
Для LockMode.Upgrade
чтобы работать, все транзакции должны быть включены в транзакцию, потому что LockMode.Upgrade
делает это заблокировать его в текущей транзакции.
Ваша проблема, скорее всего, будет связана с тем, что заявления не включены в транзакцию.
Оптимистическая блокировка применяется не к одному выражению, а к нескольким транзакциям, которые отделены друг от друга. Пример:
Начать транзакцию;
Получить запись от
Id = 42
;Завершить транзакцию.
Затем, вне сделки, увеличение Counter
,
После этого:
Начать транзакцию;
Получить запись от
Id = 42
;Проверьте, не изменился ли счетчик от значения, полученного в первой транзакции;
а. Если он не изменился, обновите счетчик с увеличенным значением;
б. Если он изменился, обработайте измененное значение.
Завершить транзакцию.
Оптимистическая блокировка означает, что вы "надеетесь" на Counter
не изменился между двумя транзакциями и обрабатывает случай, когда он изменился. С пессимистической блокировкой вы гарантируете, что все изменения сделаны в пределах одной транзакции со всеми необходимыми записями, заблокированными.
Кстати: механизм проверки (будь Counter
изменилось в это время) может автоматически обрабатываться NHibernate.