我应该在执行定期作业的单独线程中保留DbContext的实例吗

本文关键字:保留 DbContext 实例 线程 单独 执行 作业 我应该 | 更新日期: 2023-09-27 18:10:07

我有一个Worker类,它定期发送电子邮件,我从App_start((上的Global.asax.cs开始

public static class Worker
{
    public static void Start()
    {
        ThreadPool.QueueUserWorkItem(o => Work());
    }
    public static void Work()
    {
        var r = new DbContext();
        var m = new MailSender(new SmtpServerConfig());
        while (true)
        {
            Thread.Sleep(600000);
            try
            {
                var d = DateTime.Now.AddMinutes(-10);
                var ns = r.Set<Notification>().Where(o => o.SendEmail && !o.IsRead && o.Date < d);
                foreach (var n in ns)
                {
                    m.SendEmailAsync("noreply@example.com", n.Email, NotifyMailTitle(n) + " - forums", NotifyMailBody(n));
                    n.SendEmail = false;
                }
                r.SaveChanges();
            }
            catch (Exception ex)
            {
                ex.Raize();
            }
        }
    }
 }

所以我在应用程序的整个生命周期中都保持这个dbcontext的活力,这是一个好的做法吗?

我应该在执行定期作业的单独线程中保留DbContext的实例吗

DbContext是一个非常轻量级的对象。

无论您的DbContext是保持活动状态还是在进行调用之前实例化它都无关紧要,因为实际的DB连接只有在SubmitChanges或Enumerate查询时才会打开(在这种情况下,它在枚举结束时关闭(。

在您的具体情况下。这根本不重要。

有关此方面的详细信息,请阅读LinqDataContext和Dispose。

我会将其封装在Work内部的using语句中,并让数据库连接池做它的事情:

 using (DbContext r = new DbContext())
 {
     //working
 }

注意:我不能100%确定DbContext是如何处理数据库连接的,我假设它打开了一个。

在应用程序的生命周期内保持数据库连接"活动"不是一种好的做法。您应该在需要时使用连接,并通过API关闭它(使用语句将为您处理此问题(。数据库连接池实际上会根据连接需求打开和关闭连接。

我同意@rick-schott的观点,即当需要使用DbContext时,应该实例化它,而不是在应用程序的整个生命周期中保留它。有关更多信息,请参阅使用对象(实体框架4.1(,特别是关于Lifetime:的部分

在处理长时间运行的上下文时,请考虑以下内容:

  • 当您将更多对象及其引用加载到内存中时上下文的存储器消耗可能快速增加。这可能导致性能问题。

  • 如果异常导致上下文处于不可恢复状态,则整个应用程序可以终止。