【问题标题】:How to avoid the error "A second operation started on this context before a previous operation completed" in EF Core?如何避免 EF Core 中的错误“在前一个操作完成之前在此上下文上启动了第二个操作”?
【发布时间】:2022-01-06 10:58:30
【问题描述】:

我刚刚在我的 ASP.NET Core 应用程序中收到错误“在前一个操作完成之前在此上下文上启动了第二个操作”,并发现我错误地并行运行了两个查询。但是,现在我不确定我必须如何避免 DbContext 线程问题。在Avoiding DbContext threading issues 上,有人提到我不应该对同一个 DbContext 实例执行任何并行操作,但我什么时候才能在我的应用程序中使用同一个 DbContext 实例?

我在 Startup.cs 文件中的 ConfigureServices() 方法中调用 services.AddDbContext(),然后通过我的数据访问器类中的构造函数注入上下文,然后使用它对数据库执行查询。因此,由于我自己没有手动创建上下文的任何实例,因此我不完全了解上下文的实例化时间和方式。

例如,如果两个用户单击我的前端中的同一个按钮,该按钮向我的后端发起相同的请求,因此同时调用了相同的查询(假设两个用户确实执行了确切的操作同时)?两种情况下使用的是同一个 DbContext 实例,还是两个请求都有自己的 DbContext 实例?

【问题讨论】:

  • 可能你错过了await或者引入了async void方法。
  • @SvyatoslavDanyliv 也许我的问题不是很清楚,但我已经解决了我的问题。我的问题通常与此错误以及如何避免再次遇到此错误有关。这不是要解决我在项目中第一次遇到此错误的问题。
  • these answers 可能会有所帮助
  • 每个请求都将被赋予一个 DbContext 实例,因此两个或多个用户同时点击您的控制器构成两个或多个请求,每个请求都有自己的 DbContext。例如,将 DbContext 配置为 Singleton 会非常糟糕,因为 所有 请求将尝试使用相同的实例,并行操作需要特别考虑在方法调用中限定 DbContext 实例。通常我会注册并注入一个 Factory 类以在这种情况下提供一个 DbContext 或一个工作单元容器。

标签: asp.net-core dependency-injection entity-framework-core dbcontext .net-6.0


【解决方案1】:

如果您像这样配置它,AFAIK 每个 Web 请求都会使用自己的 DbContext 实例运行。

但是在请求处理期间,可能会创建多个线程(或任务),每个线程(或任务)都使用相同的实例,从而导致此错误。

enabling MARS 可以通过将 ;MultipleActiveResultSets=True 添加到您的连接字符串来解决此问题,但有限制:

  • 您的 DB Provider 需要支持它。 SQL Server 提供程序支持它,但肯定不是所有的提供程序都会这样做。
  • 并发查询必须全部使用支持的查询语句,例如2 个SELECTs 可以同时运行,但与UPDATEINSERT 并行的SELECT 可能(或将会)失败,更不用说其他类型的命令,例如CREATE。李>

由于切换开销,使用 MARS 可能会稍微减慢速度,这意味着两个并行查询总共花费的时间比一个接一个地执行它们要多。但是要确保所有请求中的所有线程或任务都同步它们的数据库访问,以便一切都串行运行可能很难完成。根据我迄今为止的经验,减速从来都不是问题,但您的情况可能会有所不同。

【讨论】:

  • 启用 MARS 无法修复相关错误 - 它纯粹来自 EF Core 同时 DbContext 实例使用保护。
猜你喜欢
  • 2019-05-25
  • 2020-11-06
  • 2021-05-04
  • 2018-11-07
  • 1970-01-01
  • 2020-06-05
  • 2019-12-17
  • 2018-07-23
  • 1970-01-01
相关资源
最近更新 更多