【发布时间】:2017-10-18 10:26:01
【问题描述】:
我知道这是一个非常笼统的问题,但请耐心等待:
我刚刚遇到了实体框架缓存,也就是 ChangeTracker。
我们拥有的是一个使用网络核心和实体核心的小型微服务。这个微服务在 IIS 后面进行负载平衡(RoundRobin)(到目前为止,我猜这没什么不寻常的)。让我们称它们为 Instance1 和 Instance2。
现在会发生什么:
我在数据库中有一个条目,例如(为简单起见,这里表示为 JSON):
{ Name: "Test", FirstName: "T." }
现在我将它加载到一个表单中(来自 Instance1 的回答)并将 FirstName 修改为 Thomas,并通过 PUT 保存它,这由 Instance2 完成。现在我再次请求获取该条目。此请求由 Instance1 响应,它将从缓存中加载此请求(因为 changetracker 表示它未更改)。因此我得到了
{Name: "Test", FirstName: "T."}
似乎有很多人对更改跟踪器有问题,一个常见的答案是每次请求都重建 dbcontext,在我看来这是完全错误的,因为这是一个非常“昂贵”的操作。
我还注意到,随着时间的推移,新数据的插入变得越来越慢,因为更改跟踪器正在填满,所以我不得不每隔一段时间回收一次微服务。
所以我的问题是: 如何在不为每个请求重新初始化 dbcontext 的情况下解决此问题? 我还找到了一些允许禁用缓存的答案,但仅适用于单个数据库操作,这意味着我必须将此选项添加到每个数据库操作中,这对我来说几乎与使用每个请求重新初始化数据库上下文一样错误。 我忽略了什么,必须有一个简单的解决方案!
【问题讨论】:
-
我认为您不应该将更改跟踪器视为缓存机制。它完全用于跟踪每个数据库上下文的更改。每个请求使用新的数据库上下文,我认为这是正确的选择。如果您需要缓存,请不要为此目的使用 db 上下文,例如使用 memcache 或 .net System.Runtime.Caching 的 buildin。当然,您仍然需要将缓存与数据库同步,但您的数据库上下文不会因跟踪(未同步)实体而变得臃肿。顺便说一句,创建新的数据库上下文是非常便宜/轻量级的操作,因为它后面有一个连接池。
-
是的,你把事情搞砸了。 DbContext 必须限定范围(每个请求一个实例),这是默认行为。您必须在某处将其作为单例。更好地使用 Redis 或类似的东西来分发缓存
-
好吧,我将数据库上下文注入到我的存储库中。我的 repo 被注入到控制器中,但是作为一个单例,所以这似乎是我的错误。如果我将我的存储库设置为 Scoped,那么它应该在每个请求中创建,然后将新的数据库上下文注入其中?我明天会试试这个,谢谢你的回答!
-
@vasiloreshenski
creating new db context is very cheap/light operation because there is a connection pool behind it.你确定这是真的吗? -
@Mardoxx 不,连接池不是由数据库上下文处置或由 EF 控制。检查此msdn.microsoft.com/en-us/library/orm-9780596520281-01-16.aspx。它声明如下:'由于连接池由数据库提供者控制,实体框架不会显式影响连接池的工作方式或与之交互。相反,它依赖于提供者的连接池”。
标签: c# entity-framework asp.net-core microservices