Я пытаюсь обновить Quantity
Product
в системе продаж с использованием NHibernate.
using (var session = NHibernateSessionUtil.OpenSession())
{
using (var trans = session.BeginTransaction())
{
var product = session.Load<Product>(1);
product.Quantity += 2;
session.SaveOrUpdate(product);
trans.Commit();
}
}
Однако NHibernate сгенерирует SQL в этой форме:
UPDATE Product SET quantity = 2 WHERE id = 1;
Если другой клиент обновляет количество товара во время обработки этого кода, оно будет неверно .
Решение, о котором я могу думать до сих пор, заключается в блокировке этой строки перед обновлением:
...
var product = session.Load<Product>(1);
// lock row for update
session.Lock(product, LockMode.Upgrade);
product.Quantity += 2;
session.SaveOrUpdate(product);
...
Однако это может повлиять на другого клиента, если мне потребуется обновить длинный список продуктов.
Существует ли в NHibernate эквивалентный метод для генерации SQL, например:
UPDATE Product SET quantity = quantity + 2 WHERE id = 1;
?
есть предложения?
Обновление
Я попытался открыть сеанс с сериализуемым уровнем изоляции, как предложил @Fran:
...
using (var trans = session.BeginTransaction(IsolationLevel.Serializable))
...
Проблема заключается в том, что при изменении строки другим клиентом до совершения этой транзакции возникает исключение:
{"ERROR: 40001: could not serialize access due to concurrent update"}
означает ли это, что нам нужно явно заблокировать каждую строку, которая требует обновления? т.е.:
var product = session.Load<Product>(1, LockMode.Upgrade);
если блокировка необходима, чем отличается транзакция открытия от IsolationLevel.Serializable ?