【问题标题】:What happens, if I accidentally don't dispose the Entity Framework context?如果我不小心不释放实体框架上下文会发生什么?
【发布时间】:2021-12-31 11:43:53
【问题描述】:

让我们假设一个简单的 ASP.NET MVC 控制器:

public class SomeController : Controller
{
    public ActionResult SomeAction()
    {
        var db = new SomeDataContext(); // without 'using' or 'await using'
        var models = db.Models.ToList();
        return this.View(models)
    }
}

如果我忘记了using-statement,究竟会发生什么?上下文永远不会暴露吗?它会泄漏内存吗?真的是死罪吗?

【问题讨论】:

  • 它会泄漏一个打开的连接,最终导致连接池饥饿,Stack Overflow上有很多帖子,例如stackoverflow.com/questions/64261113/…。最终它们通常会被 GC 处理掉,但这可能需要一些时间(如果有的话),而且通常速度不够快,无法避免饥饿。拥有using 区块真的要花钱吗?

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


【解决方案1】:

这将留下一个打开的数据库连接,并为所有被跟踪的实例分配内存,直到垃圾收集发现引用都没有被使用并真正释放它们。

因此,如果您的 Models 表有 100k 行:

    var db = new SomeDataContext(); // +1 connection from the connection pool when first query is run.
    var models = db.Models.ToList(); // +100k loaded entities.

以单个用户的身份对此进行测试,除非您开始查看内存使用情况,否则您不会看到太多...将其部署到拥有 100 多个用户的 Web 服务器上,这些用户发出并发请求并观察您的 Web 服务器运行情况自己被遗忘了。

另外,避免将实体返回到视图中,只需使用 Select() 或 Automapper 的 ProjectTo() 将您需要的数据投影到 ViewModel/DTO 中。 (不要使用 Automapper 的 Map())这不仅可以避免相关数据的延迟加载命中等陷阱,而且还可以产生更高效/更快的查询。

始终处置您的 DbContext 实例。这意味着要么使用 using 块,要么设置依赖注入来管理注入的 DbContext 的生命周期范围,范围为网站/服务的每个 HTTP 请求。

【讨论】:

  • 垃圾收集(或终结器)会关闭与数据库的连接吗?
  • 最终,可能...当然当您的应用程序池由于异常而循环时... :) 最终没有理由设置要管理的 DbContext通过 IoC 容器为网站提供服务并将上下文实例的范围管理到 HTTP 请求。这不是一个真正值得问“如果我不这样做怎么办”的问题,而是要了解如何正确地做到这一点以避免在未来遇到问题。
猜你喜欢
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
  • 2018-05-13
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多