Как справиться с этим сценарием параллелизма с помощью NHibernate + asp.net mvc? - PullRequest
3 голосов
/ 08 июня 2011

Контекст: веб-приложение, написанное на asp.net MVC + NHibernate. Это карточная игра, в которой игроки играют одновременно, поэтому их действия могут одновременно изменять одно и то же поле сущности (все они делают x = x + 1 на поле). Кажется довольно классическим, но я не знаю, как справиться с этим.

Само собой разумеется, я не могу представить всплывающее окно пользователю, говорящее: "Сущность была изменена другим игроком. Объединить или отменить?". Когда вы думаете, что это связано с действием на карту, я не могу вмешиваться, как это. Мое приложение должно внутренне обрабатывать этот сценарий. Так как поле находится в классе сущности, и у каждого сеанса есть свой экземпляр сущности, я не могу просто взять блокировку CLR. Означает ли это, что я должен использовать пессимистический параллелизм, чтобы каждый веб-запрос, действующий на эту сущность, ставился в очередь, пока игрок не завершил свое действие? На практике это означает, что каждый запрос PlayCard должен использовать блокировку?

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

Спасибо

Ответы [ 2 ]

1 голос
/ 08 июня 2011

В зависимости от вашей бизнес-логики может иметь смысл попробовать кэширование второго уровня. Это может быть хорошо в зависимости от продолжительности игры и от того, как в нее играют. Поскольку кэш второго уровня существует на уровне фабрики сеансов, фабрика сеансов должна управляться в соответствии со временем жизни игры. Сеанс Nh может быть создан для каждого запроса, но порожденный фабрикой сеансов, настроенной для кэширования второго уровня, означает, что интересующие данные кэшируются во всех сеансах. Преимущество использования кэша второго уровня заключается в том, что вы можете настроить его для каждого класса отдельно - кэшировать только те объекты, которые вам нужны. Он также предоставляет различные стратегии параллелизма в зависимости от поставщика кэша. Несмотря на то, что это может перенести проблему параллелизма с уровня DB на сеанс NH, это может дать вам лучший вариант для решения вашей ситуации. Есть некоторые недостатки в использовании этого, но его пригодность все зависит от вашей бизнес-логики.

1 голос
/ 08 июня 2011

Вы можете попробовать применить оптимистическую блокировку следующим образом:

Объект БД будет иметь версию объекта отслеживания столбца ( nhibernate.info ссылка ).

Если вы получаете исключение «устаревшая версия» при сохранении сущности (= изменено другим пользователем) - перезагрузите сущность и попробуйте снова. Затем отправьте обновленное значение клиенту.

Насколько я понимаю, ваш сервер получает запрос от клиента, затем открывает сеанс, вносит некоторые изменения и обновляет сущности, закрывая сеанс. В этом случае ни один поток не будет удерживать один объект в памяти слишком долго, и конфликты оптимистической блокировки не должны возникать слишком часто.

Таким образом, вы можете избежать многих заблокированных потоков, ожидающих завершения операции.

С другой стороны, если вы ожидаете, что повторные попытки будут происходить слишком часто, вы можете попробовать блокировку SELECT FOR UPDATE при загрузке вашей сущности (используя LockMode.Upgrade в методе NH Get). Хотя я нашел поток, который не рекомендует мне использовать это с SQL Server: SO link .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...