Атомный "вставить, если не существует" с NHibernate - PullRequest
1 голос
/ 15 сентября 2011

Рассмотрим приложение, которое делает что-то вроде:

var user = session.QueryOver<User>().Where(x => x.Name==name).SingleOrDefault();

if (user == null)
{
    user = new User(name);
    session.Save(user);
}

Бизнес-правила гласят, что имя пользователя должно быть уникальным, и это подтверждается UNIQUE INDEX в базе данных. Приведенный выше код работает просто отлично, пока два пользователя не попытаются одновременно зарегистрироваться под одним и тем же именем, оба получат user == null и попытаются создать новый User. Первый из них будет успешно завершен, второй завершится ошибкой с исключением из базы данных.

Один из способов избежать таких состояний гонки - это обернуть критический код в блок lock { }, но это не поможет, когда несколько экземпляров приложений работают с одной и той же базой данных. Теперь, если бы я только мог использовать механизмы блокировки RDBS (в данном случае MS SQL)…

Вот где я застрял. Из того, что я могу прочитать в документах NHibernate, я мог бы решить эту проблему, добавив некоторую подсказку к моей цепочке QueryOver(), запрашивающей явную блокировку. Это должна быть блокировка таблицы, поскольку у меня еще нет реальных строк. Это возможно? Как

В качестве альтернативы, могу ли я повысить уровень изоляции транзакции и автоматически получить необходимые блокировки? Учитывая, что другие (не проблемные) запросы выполняются в одной и той же рабочей единице, я подозреваю, что такого рода изменения могут привести к большому количеству блокировок / ожиданий. Это так?

Ответы [ 2 ]

2 голосов
/ 15 сентября 2011

Увеличьте уровень изоляции до Сериализуемого. Это будет блокировать как чтение, так и запись по всему запросу, включая ваше предложение where

0 голосов
/ 15 сентября 2011

Убедитесь, что запросы выполняются в том же сеансе NHibernate, что и при сохранении. Это позволит вам использовать ту же транзакцию, автоматически используя механизмы блокировки базы данных.

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

...