【问题标题】:Multi-threading problems on Entity Framework CoreEntity Framework Core 上的多线程问题
【发布时间】:2019-04-16 15:27:03
【问题描述】:

我在 ASP.NET CORE 应用程序上使用 Entity Framework 作为与数据库通信并在其上获取/写入信息的方式。 (用作非常基本的 API,充当单独应用程序的服务器。)

客户有时会提出加入特定大厅的请求。我刚刚确认,如果同时有4个请求进入,他们都会在大厅注册,但玩家数量没有更新,如果更新了 - 它会超过顶部/限制。

我是否使用了错误的实体框架?是否有替代工具可用于此类事情,或者我应该让它使用单个线程(如果有人可以提醒我如何),还是使用锁定块语句封装我的所有操作/端点?

无论我如何构建我的代码,都容易出现这些同时发生的 http 请求,在我的存储库/上下文中并行移动。

如果我可以制作某种队列,那就太好了,我相信这就是将所有内容封装在锁中的效果。

编辑:

正如vasily.sib 所回答的那样,我可以使用并发令牌来解决这个问题。请查看他的评论,了解有关如何使用它们的一些惊人信息!

【问题讨论】:

  • 你能分享你的代码sn-p吗?
  • “我使用实体框架错了吗?” - 等一下,我将使用我的心灵感应超能力......是的,我现在明白了。你用错了。
  • 每个请求都会实例化不同的 DbContext 实例,不同的 DbContext 实例应该可以在不同的线程中正常工作。
  • 现在认真:在谷歌搜索 “ef 核心并发” 0.37 秒后查看what I have found(和another useful link)。您实际寻找的是乐观并发控制。
  • @vasily.sib 我现在就试试,我想这可能是我的开销!

标签: c# asp.net-core entity-framework-core


【解决方案1】:

你的问题是这样的操作......

_context.Sessions.FirstOrDefault(s => s.Id == sessionId).PlayerCount += 1;
_context.SaveChanges();

...不是原子的。使用FirstOrDefault,您将获得会话(您在没有null 检查的情况下取消引用,因此First 将是一个更好的选择,因为您会收到更好的错误消息)。然后在另一个步骤中保存更改。在这些步骤之间,另一个并发线程可能已更改并已为 PlayerCount 保存了一个新值。

有多种方法可以解决这个问题,其中大多数都需要在数据库级别进行一些更改。

解决它的一种方法是编写一个可以自动更新的存储过程。您需要一个类似于此的UPDATE 语句:

UPDATE Sessions
SET PlayerCount = PlayerCount + 1
FROM Sessions
WHERE Id = @SessionId

如果您不想使用存储过程,您可以将此 SQL 直接发送到数据库。

此解决方案的一个问题是稍后您也执行此步骤:

if (thisSession.Size == thisSession.PlayerCount)
{
    thisSession.Status = SessionStatus.Active;
    _context.SaveChanges(); // this can be trimmed and added at the previous scope
}

您必须将其集成到您的UPDATE 语句中以保持操作的原子性。如果您想添加额外的步骤,事情可能会变得复杂。

另一种方法是使用 EF 核心内置的乐观并发。简而言之,这意味着当您保存数据时,ef 将首先检查目标行与您检索时相比是否仍处于同一版本。

为此,您的会话需要一个包含版本计数器的列。对于 SQL Server,这将是 rowversion 类型的列。拥有本专栏后,EF 就可以发挥其乐观并发的魔力。 EF 将抛出您必须处理的DbUpdateConcurrencyException。有不同的方法可以解决错误。一种简单的方法是重复整个操作,直到成功为止。

【讨论】:

  • 我是否在我的实体模型中为 rowversion 添加一个属性,或者我究竟如何在 EF 核心中实现它?到目前为止,我对所有属性都使用了 [并发] 限制。
  • 如果使用 [ConcurrencyCheck] 适合您,那很好。否则,您将需要定义一列 rowversion 类型的列,EF 将自动将其用于并发。
猜你喜欢
  • 2017-09-30
  • 1970-01-01
  • 2019-04-13
  • 2018-11-05
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
  • 1970-01-01
  • 2020-02-06
相关资源
最近更新 更多