【问题标题】:Is it ok to inject DbContext as singleton when there is only read operations?当只有读取操作时,可以将 DbContext 作为单例注入吗?
【发布时间】:2020-10-28 07:14:29
【问题描述】:

我了解DbContext 不是线程安全的,加上DbContext 缓存数据,当多个事务尝试将自己的更改保存/提交到数据库时可能会导致数据不一致。因此,强烈建议按请求注入它 (here)。但我有一种情况,即仅存在读取操作(在独立类库中)并且没有事务或创建/更新/删除操作。
我的问题是:在这种情况下将DbContext 作为单例注入是否安全?

【问题讨论】:

  • 我的问题是:为什么?为什么不让依赖注入做它最擅长的事情,并且在很长一段时间内都做得很好呢?你希望通过使用单例获得什么?
  • 我会说不,因为虽然没有数据库写入 - EF 本身在从数据库读取时将数据写入其内部结构,当库开发人员明确告诉您时,谁知道多线程时的行为方式库不是线程安全的。
  • @FranzGleichmann 因为 1) 每次调用其方法时,我都会多次调用 dbContext,我需要为每个方法添加 using(scope){create dbcontext()} 语句,这会污染代码。 2) 每个方法都应该在非常高的音量上被调用,并且每次调用实例化DbContext 10 次可能会使服务器瘫痪(即使在使用 DbContextPool 时)。 3)为什么你不反过来想?为什么我们不将它作为单例注入(并切断与作用域DbContext 相关的所有麻烦)以这种方式使用它是安全的?
  • @Evk "EF 本身在从数据库读取数据的同时将数据写入它的内部结构" 你能给我一个提到的链接吗?
  • 不,但这只是常识。您自己说DbContext 缓存数据,这就是写操作(这意味着它将缓存的实体写入内部结构的某处,以便稍后返回)。在他们的 github repo 中也有很多关于线程安全的问题。例如这里:github.com/dotnet/efcore/issues/18148 EF Core dev 再次重复:“DbContext 不是线程安全的。警告部分“EF Core 不支持在同一上下文实例上运行多个并行操作。”适用于 每个操作,而不仅仅是“保存”记录。”

标签: c# .net entity-framework ef-core-3.1


【解决方案1】:

Entity Framework 开发人员明确表示 DbContext 对于在其上执行的任何操作不是线程安全的,而不仅仅是编写(添加、保存更改等)操作,您应该相信他们如果你不想有一天花几天时间调试神秘的故障。

即使在读取操作中,EF 也可以在其内部结构上执行内存写入操作,这些结构不是线程安全的,您无法确定它在任何给定情况下都不会这样做。比如来自documentation的关于查询返回的结果集的处理:

如果查询是跟踪查询,EF 会检查数据是否代表 实体已经在上下文实例的更改跟踪器中

因此,如果查询是跟踪查询 - 它会检查当前实例的更改跟踪器,以查找具有相同键的已存在的此类实体,这意味着如果此类实体不存在 - 它会将其放入更改跟踪器。这是写操作,不安全。

你可以说,好吧,那我就用AsNoTracking()。但是here 是另一个问题,关于并发AsNoTracking 查询 - EF 甚至不允许您执行它们。图书馆维护者说:

不可能同时使用同一个 DbContext - 不仅仅是 用于跟踪查询。具体来说,一个 DbContext 有一个底层 DbConnection 到数据库,不能同时使用。那里 是在引擎盖下工作的其他各种组件 支持多线程。

但是,实例化几个 DbContext 并没有错 并对它们执行查询——无论是跟踪还是非跟踪。那 应该让你得到你正在寻找的行为。如果你遇到任何 如有其他问题,请随时回帖。

因此,存在未记录的内部组件,它们不是线程安全的,您无法确定从多个线程对 DbContext 执行任何操作时不会碰到此类组件。

【讨论】:

    猜你喜欢
    • 2019-04-27
    • 2015-02-18
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    • 2011-05-27
    相关资源
    最近更新 更多