【问题标题】:Is my DB connection closed? (Linq to Sql)我的数据库连接是否关闭? (Linq 到 Sql)
【发布时间】:2010-02-28 19:13:50
【问题描述】:

我正在使用 Linq to SQL,并阅读了有关尽快关闭数据库连接的博客文章。例如,他们展示了一个被转换为列表的变量(使用 .ToList()),而不是实际返回 Linq 查询。我有以下代码:

 public static bool HasPassword(string userId)
 {

    ProjDataContext db = new ProjDataContext();

    bool hasPassword = (from p in db.tblSpecUser
                                    where p.UserID == userId
                                    select p.HasPassword).FirstOrDefault();


    return hasPassword;
 }

这个查询可以吗?或者数据库连接会保持打开的时间超过必要的时间?

感谢您的建议

【问题讨论】:

    标签: c# database performance linq-to-sql database-connection


    【解决方案1】:

    连接将被自动管理。但是,有(或至少可以像 cmets 建议的那样)与 DataContext 关联的其他资源。在垃圾收集器销毁 DataContext 之前,这些资源不会被释放。因此,当您不再需要 DataContext 时,通常最好确保调用 dispose。

    using (ProjDataContext db = new ProjDataContext()) {
        bool hasPassword = (from p in db.tblSpecUser
                                        where p.UserID == userId
                                        select p.HasPassword).FirstOrDefault();
    
    
        return hasPassword;
    }
    

    这里确保在 using 块退出时调用db.Dispose(),从而显式关闭连接。

    编辑:在讨论之后,我查看了 DataContext dispose(也使用 Reflector)并找到了从 DataContext.Dispose 调用的以下代码(FW 3.5):

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (this.provider != null)
            {
                this.provider.Dispose();
                this.provider = null;
            }
            this.services = null;
            this.tables = null;
            this.loadOptions = null;
        }
    }
    

    所以资源被释放:

    • 提供者可能持有DbConnection、日志 (TextWriter) 和DbTransaction
    • CommonDataServices
    • 表格字典。
    • LoadOptions

    提供者可能持有需要处置的资源(DbConnectionDbTransaction)。此外,可能必须处理日志的TextWriter,具体取决于用户分配给DataContext 的日志机制的TextWriter 实例,例如一个 FileWriter,然后自动关闭。

    据我所知,其他属性只有内存,但也可以通过 dispose 方法进行垃圾收集,但是,它不能确定内存何时实际被释放。

    所以,最后我完全同意 casparOne 的说法:

    一般来说,像这样共享数据访问资源是个坏主意。

    您应该创建资源来访问数据库、执行您的操作,然后在完成后将其丢弃。

    【讨论】:

    • 哇,感谢您的快速回复!我将替换我的所有 projdatacontext 代码以使用“使用”方法,而不是创建一个新实例并等待其 Dispose 方法被调用。再次感谢您的帮助。
    • 值得注意的是,虽然IDisposable是在Linq to SQL中实现的,但是Linq to SQL的设计者明确指出DataContext确实不需要需要被disposable,大部分的时间。见stackoverflow.com/questions/821574/…
    • 感谢您的信息。如果我理解正确,这是否意味着虽然在您需要更严格地控​​制 GC 时间时使用“使用”是很好的,但在您使用 DataContext 时(大部分时间)并不需要它?
    • @o-logn:这是我的理解。
    • @casperOne:Dispose 方法释放provider 成员,并将servicestablesloadOptions 成员设置为空。 SqlProvider 中的 Dispose 方法(由 DataContext Dispose 方法调用)关闭 connection 成员,并将一堆其他成员设置为 null。所以我不会说它什么都不做。
    【解决方案2】:

    实现的角度来看,不,您无需担心任何事情。不过这不是查询的原因,而是DataContext本身的管理。

    DataContext 类实现了IDisposable 接口,因此您应该在完成后调用 DataContext 实现上的 Dispose。

    现在是well known fact that calling Dispose on DataContext instances do nothing, and therefore are not technically required

    不幸的是,这也是非常糟糕的做法。您应该始终针对合约而不是实现进行编码。因为 DataContext 实现了 IDisposable,所以您应该关闭它,即使您知道它什么都不做,因为这可能绝对在未来的实现中发生变化。

    此外,如果您切换到另一个 LINQ 提供程序,例如 LINQ-to-Entities,那么您必须在完成后调用 Dispose,因为 ObjectContext 实例中的数据库连接的生命周期(其中也实现了 IDisposable) 是非常不同的,对 Dispose 的调用会对那些数据库连接产生影响。

    话虽如此,你有一个更大的担忧。如果您共享一个 DataContext,您将面临跟踪太多对象的风险。除非您将 ObjectTrackingEnabled property 设置为 false,否则 DataContext 将跟踪通过它选择的每个对象。如果您在应用程序的整个生命周期内没有执行更新操作(或者即使您执行了更新操作),则专用于共享 DataContext 上的对象跟踪的资源数量可能会变得相当可观。

    使用其他数据库技术(例如classes in the System.Data.SqlClient namespace)开发的规则仍然适用。

    一般来说,像这样共享数据访问资源是个坏主意。

    您应该创建资源来访问数据库、执行操作,然后在完成后将其丢弃。

    【讨论】:

    • 感谢您的帖子。我发布的代码几乎就是我在 DAL 中实现所有方法的方式。如果我在代码中为每个方法创建一个新实例,我是否仍然共享 DataContext?
    • @o-logn:不,如果您在需要时创建一个新实例(例如,在 using 语句中,在每个操作中创建和处置它),那将是“针对合同进行编码" 如上所述,以及使用 DataContext 实例的正确方法,IMO。
    • 啊,这是一种解脱。以为我正在参加一个巨大的重新编码会议:)。谢谢!
    【解决方案3】:

    使用 Linq-To-SQL,您通常不需要特别关注作为上下文对象(示例中的 db)一部分的连接的打开和关闭。您唯一需要专门执行此操作的情况是,如果您通过上下文对象发送直接 SQL 调用,而不是使用 Linq。

    使用 L2S,您通常希望创建上下文对象,完成您的工作单元,然后尽快处置该对象。您的代码示例对我来说看起来不错。

    【讨论】:

      【解决方案4】:

      我认为使用 using 语句是一个好习惯。但我认为您的查询没有什么不好。

      public static bool HasPassword(string userId)
       {
      
          using(var db = new ProjDataContext())
          {
      
             bool hasPassword = (from p in db.tblSpecUser
                                          where p.UserID == userId
                                          select p.HasPassword).FirstOrDefault();
      
      
              return hasPassword;
          }
      }
      

      【讨论】:

        【解决方案5】:

        数据库连接将在您的 db 对象不再存在(处置)或显式关闭后立即关闭。 在您的示例中,它将(迟早)被垃圾收集。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多