Рассмотрим приложение, которое делает что-то вроде:
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()
, запрашивающей явную блокировку. Это должна быть блокировка таблицы, поскольку у меня еще нет реальных строк. Это возможно? Как
В качестве альтернативы, могу ли я повысить уровень изоляции транзакции и автоматически получить необходимые блокировки? Учитывая, что другие (не проблемные) запросы выполняются в одной и той же рабочей единице, я подозреваю, что такого рода изменения могут привести к большому количеству блокировок / ожиданий. Это так?