【问题标题】:Concurrent request handling in MVC3 / EF4MVC3 / EF4 中的并发请求处理
【发布时间】:2011-12-13 19:27:07
【问题描述】:

我有一个Games 用户可以加入的列表。要选择game,他们必须在该游戏中选择position(即角色)。

型号

[Game] 1 <-> * [PlayerGame] * <-> 0..1 [Player]

PlayerGame 实体定义玩家选择的位置。

其他详情

  • 所有游戏都列在 MVC 3 视图中。
  • 数据保存在 SQL Server 2008 实例中,并通过 EF4 (CodeFirst) 访问。
  • 视图通过一些 jQuery Get() 调用自行更新,这些调用每 N 毫秒提取最新数据。
  • 延迟越高 (N),出现竞速条件的机会就越大,即 2 个用户会尝试选择相同的位置。
  • 如果两个用户同时选择相同的位置,我显然需要进行一些服务器端验证,以仅允许 2 个用户中的一个获得所选位置。

评估只有 1 人获得所选职位而其他人收到错误消息的最佳方法是什么?

我目前正在考虑使用时间戳来确保 2 个调用中只有 1 可以成功更新 PlayerGame 行。这是个好主意吗?

【问题讨论】:

    标签: asp.net-mvc-3 model-view-controller entity-framework-4 concurrency


    【解决方案1】:

    是的,使用时间戳。这是通常使用的方式,SQL 服务器(任何数据库服务器)和 EF 都支持它们。您必须将时间戳往返于客户端并在构建要更新的实体时使用它(在分离的场景中)。

    【讨论】:

    • TimeStamps 的主要问题是我必须在创建游戏的同时创建每个 PlayerGame 实体。因此 PlayerGame.PlayerId 必须可以为空。不过这也没什么大不了的!
    【解决方案2】:

    根据您的问题,我可以假设您也有一个 [Positions] 表?如果没有,这些是从哪里来的?

    所以你真的不必有时间戳,对吧?就在你坚持你的实体之前,做一些类似entity.List().Where(x =&gt; x.GameId == requestedGameId &amp;&amp; x.PositionId == requestedPositionId)

    然后,如果您收到 null 并且它尚不存在,则可以安全提交,如果您收到实体,则该职位已被占用。

    注意:我对实体框架语法不太熟悉,只是猜测它会是什么样子,但你可能会明白我的伪代码的意思

    【讨论】:

    • 是的,有一个Position值,它是PlayerGame的一个属性。您的解决方案的问题在于,可以在玩家 B 尝试更新行的同时(或者说,1 毫秒后)检查玩家 A 是否已经占据了该位置。这些比赛条件意味着玩家 A 不会收到错误消息,但他的位置会被玩家 B 抢走,我显然不希望这样。
    • 好吧,另一种解决方案是在数据库层的GameIdPositionId 上添加一个候选键。 (这就像多列的唯一约束)如果播放器 B 尝试插入并且该组合已经存在,则 sql server 将拒绝。
    • 啊,这是个好主意!不知道如何使用 CodeFirst 生成此密钥...我将不得不看看它是否比使用 TimeStamps 更简单,感谢您的提醒!
    • 如果实体框架没有一直重新创建你的数据库,你可以在你的数据库上手动实现它。但是,如果 EF 假设它可以插入但从服务器接收到错误,它可能会抛出异常。
    • 此外,在最深层次(您的 sql 服务器)上实施此规则的 imo 似乎是一个好习惯。这样,即使数据是从其他地方插入的(例如直接查询),您仍然可以确保其正确,并且不会与您在更高级别(例如 EF)中实施的规则发生冲突
    猜你喜欢
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-16
    • 2021-05-01
    • 2019-04-22
    • 1970-01-01
    相关资源
    最近更新 更多