6

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

我的理解是 DbContext 实例不应该在并发 Web 请求之间共享,所以绝对不应该跨线程共享。但是如何在非并发 Web 请求中共享它呢?

由于线程敏捷性ASP.Net 中的线程敏捷性是什么意思?),一个线程在死亡之前可以处理多个 Web 请求是对的吗?

如果是这样,为每个线程依赖注入一个 DbContext 实例是否安全?

原因是我使用的是 Unity,它不包括每个请求的生命周期选项。从MVC,EF - DataContext 单例实例 Per-Web-Request in Unity,我想我可以使用自定义 LifetimeManager;我只是想知道使用 PerThreadLifetimeManager 是否安全且足够。

4

2 回答 2

6

为每个线程依赖注入一个 DbContext 实例是否安全?

这取决于。如果您的想法是DbContext每个 Web 请求都有一个,并且您的应用程序的一致性取决于它,那么DbContext每个线程有一个不是一个好主意,因为单个 Web 请求仍然可以获取多个 DbContext 实例。并且由于 ASP.NET 池线程,每个线程缓存的实例将在整个应用程序的持续时间内存在,这对 a 非常不利DbContext(如此所述)。

另一方面,您可能会想出一个缓存方案,以确保DbContext单个 Web 请求使用一个,并在请求完成时返回到池中,以便其他 Web 请求可以获取它。这基本上就是 .NET 中连接池的工作方式。但是由于DbContext实例缓存数据,该数据很快就会变得陈旧,因此即使您能够提出线程安全的解决方案,您的系统仍然会以不一致的方式运行,因为在某些看似随机的时刻,旧数据会显示为用户,同时在以下请求中显示新数据。

我认为可以DbContext在 Web 请求开始时清除 's 缓存,但这基本上与为该请求创建新缓存相同DbContext,但缺点是性能要慢得多。

我只是想知道使用 PerThreadLifetimeManager 是否安全且足够。

不,由于上述原因,它不安全。

但实际上在每个 Web 请求的基础上注册一个 DbContext 非常容易:

container.Register<MyApplicationEntities>(new InjectionFactory(c => {
    var context = (MyApplicationEntities)HttpContext.Current.Items["__dbcontext"];

    if (context == null) {
        context = new MyApplicationEntities();
        HttpContext.Current.Items["__dbcontext"] = context;
    }

    return context;
})); 
于 2013-11-01T08:46:48.560 回答
1

如果您将在每个请求中使用多个 DbContext,您最终可能会得到一个多线程应用程序,很有可能会丢失数据完整性。一个网络请求可以被视为一个事务;但是使用 PerThreadLifeTimeManager 你会有多个不同的事务,这些事务不相关,但也许它们应该。例如,发布一个包含许多数据的表单最终可能会保存多个数据库表,并且有 2 个或更多独立上下文可能会发生一个插入成功但另一个失败并且您可能有不一致的数据。

另一个重要的事情是 ASP.NET 基础结构使用线程池,因此每个启动的线程都将在请求完成后被重用,如果一个请求中出现问题,它可能会影响另一个请求。这就是为什么不建议在线程池环境中使用任何 Thread-LocalStorage(线程中的静态),因为我们无法控制线程的生命周期。

于 2013-11-01T07:53:59.850 回答