如何使用NHibernate + asp.net mvc处理这种并发场景?

时间:2011-06-08 13:55:12

标签: asp.net-mvc nhibernate concurrency

上下文:用asp.net MVC + NHibernate编写的Web应用程序。这是一个纸牌游戏,玩家可以同时玩游戏,这样他们的动作可能同时修改一个实体的同一个领域(他们都在场上做x = x + 1)。看起来很古典,但我不知道如何处理它。

毋庸置疑,我无法向用户显示弹出窗口“实体已被其他玩家修改过。合并或取消?”。当你认为这与卡的动作有关时,我不能这样干涉。我的应用程序必须在内部处理这种情况。由于该字段位于实体类中,并且每个会话都有自己的实体实例,因此我不能简单地进行CLR锁定。这是否意味着我应该使用悲观并发,以便每个作用于此实体的Web请求排队,直到玩家完成其操作?实际上,这意味着每个PlayCard请求都应该使用锁?

请不要将我发送给有关并发或类似的NH doc。我正在使用在这种情况下应该使用的技术,而不是如何在NH中实现它。

由于

2 个答案:

答案 0 :(得分:1)

您可以尝试以这种方式应用乐观锁定:

数据库实体将具有列跟踪实体版本(nhibernate.info link)。

如果在保存实体时遇到“陈旧版本”异常(=由其他用户修改) - 重新加载实体并重试。然后将更新后的值发送给客户端。

据我所知,您的后端收到来自客户端的请求,然后打开会话,进行一些更改并更新实体关闭会话。在这种情况下,没有线程会将一个实体在内存中保留太长时间,乐观的锁定冲突不应该经常发生。

这样可以避免让许多锁定的线程等待操作完成。

另一方面,如果您希望重试过于频繁,则可以在加载实体时尝试SELECT FOR UPDATE锁定(在NH Get方法中使用LockMode.Upgrade)。虽然我找到了阻止我在SQL Server中使用它的线程:SO link

通常,解决方案取决于游戏的逻辑以及您是否可以在不向用户显示消息的情况下解决代码中的并发冲突。我还使用最新数据进行UI更新,以避免玩家对过时的游戏情况采取行动,然后对结果感到惊讶。

答案 1 :(得分:1)

根据您的业务逻辑尝试二级缓存可能有意义。根据游戏的长度和游戏方式,这可能是一个很好的选择。由于第二级缓存存在于会话工厂级别,因此必须根据游戏的生命周期来管理会话工厂。可以为每个请求创建Nh会话,但是由为第二级高速缓存配置的会话工厂生成意味着在所有会话中高速缓存感兴趣的数据。使用二级缓存的优点是您可以逐个类地配置它 - 仅缓存您需要的实体。它还根据缓存提供程序提供各种并发策略。尽管这可能会将并发问题从数据库级别转移到NH会话,但这可能会为您提供更好的选择来处理您的情况。有使用它的问题,但它的适用性取决于你的业务逻辑。