ef-core 中的 DbContext 和 DbcontextPool

nam*_*dar 6 multithreading dependency-injection dbcontext entity-framework-core .net-core

我阅读了很多有关 Efcore 中的 DBcontext 及其生命周期的文档和文章,但是,我有一些问题。

基于此链接“ https://learn.microsoft.com/en-us/ef/core/dbcontext-configuration /” DBcontext 的最佳生命周期和 AddDbContext 的默认生命周期是scope,但是下面两者存在矛盾本文档中的句子。

DbContext 不是线程安全的。不要在线程之间共享上下文。请确保在继续使用上下文实例之前等待所有异步调用。”

另一方面,也有人提到,

“在大多数 ASP.NET Core 应用程序中,Dbcontext 不会出现并发访问问题,因为在给定时间只有一个线程执行每个客户端请求,并且每个请求都有一个单独的依赖项注入范围(因此有一个单独的 DbContext 实例)。”

  1. 我很困惑将 DBcontext 注册为范围服务是否是线程安全的?
  2. 将DBcontext注册为单例服务具体有哪些问题?

此外,我阅读了一些禁止注册单例 DbContext 的文档,但是AddDbContextPool 允许注册单例 DBcontext。所以有一些关于Dbcontextpool的问题。

  1. 使用 DbContextPool 而不是 DbContext 有什么影响?
  2. 我们什么时候应该使用它,使用contextPool时应该考虑什么?
  3. DbContextPool 是线程安全的吗?
  4. 由于在应用程序的整个生命周期中存储大量数据库集实例,是否会出现内存问题?
  5. 更改跟踪或 ef 的任何部分将失败或不在数据库上下文池中?

每个 Web 请求一个 DbContext...为什么?

.NET 实体框架和事务

Ste*_*ven 9

我理解为什么您认为 Microsoft 文档中的语言令人困惑。我来为你解开:

  • “DbContext 不是线程安全的。” 该语句意味着从多个线程并行访问 DbContext 是不安全的。堆栈溢出答案您已经引用过,解释一下。
  • “不要在线程之间共享上下文。” 这种说法很令人困惑,因为异步(async/await)操作倾向于跨多个线程运行,尽管从来不是并行的。更简单的说法是:“不要在 Web 请求之间共享上下文”,因为单个 Web 请求通常运行单个工作单元,尽管它可能异步运行其代码,但它通常不会并行运行其代码。
  • “Dbcontext 在大多数 ASP.NET Core 应用程序中不会出现并发访问问题”:这段文字有点误导,因为它可能会让读者相信 DbContext 实例是线程安全的,但事实并非如此。作者在这里想说的是,使用默认配置(即使用 )AddDbContext<T>(),ASP.NET Core 确保每个请求都有自己的DbContext实例,因此默认情况下“不会受到并发访问的影响”。

1 我很困惑将 DBcontext 注册为作用域服务是否是线程安全的?

DbContext实例本身不是线程安全的,这就是为什么您应该将它们注册为Scoped,因为这会阻止它们被多个请求访问,这将使它们的使用成为线程安全的。

2 将DBcontext注册为单例服务具体有哪些问题?

这已经在您已经引用的这个答案中进行了详细描述。我认为这个答案涉及很多细节,我不会在这里重复。

此外,我阅读了一些禁止注册单例 DbContext 的文档,但是 AddDbContextPool 可以注册单例 DBcontext。所以有一些关于Dbcontextpool的问题。

DbContext 池化功能与将 DbContext 注册为单例有很大不同,因为:

使用 DbContextPool 而不是 DbContext 有什么影响?

文档中提供了有关此内容的更多信息。

我们什么时候应该使用它,使用contextPool时应该考虑什么?

当您的应用程序需要它带来的性能优势时。在决定添加之前,您可能需要对其进行基准测试。

DbContextPool 是线程安全的吗?

是的,与注册 DbContext 的方式相同,因为Scoped线程安全;如果您意外地保留了跨请求重用的对象内的 DbContext 实例,则此保证将被破坏。您必须妥善保管Scoped对象,以防止它们成为强制依赖项

由于在应用程序的整个生命周期中存储大量数据库集实例,是否会出现内存问题?

记忆损失几乎不会被注意到。对于请求结束后带回池中的每个 DbContext,都会清除所谓的一级缓存。这是为了防止 DbContext 过时并防止出现内存问题。

更改跟踪或 ef 的任何部分将失败或不在数据库上下文池中?

不,事实并非如此。在大多数情况下,使 DbContext 池化只需要进行基础结构更改(更改应用程序的启动路径),并且在很大程度上对应用程序的其余部分是透明的。但再次强调,请务必阅读本文以熟悉使用 DbContext 池的后果。