我的数据库连接是否已关闭?(Linq to Sql)

4

我正在使用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;
 }

这个查询是否合适?还是数据库连接会比必要的时间更长地保持打开状态?

感谢任何建议。

5个回答

5

连接将自动管理。不过,根据评论所述,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),发现以下代码(FW 3.5)将从DataContext.Dispose中调用:

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实例,例如一个文件写入器,然后自动关闭。

据我所知,其他属性只占用内存,但是通过处理方法,也可以将其释放以进行垃圾回收,但是不能确定实际释放内存的时间。

因此,最后我完全同意casparOne的说法:

一般来说,共享数据访问资源是不好的做法。

您应该创建用于访问数据库的资源,在完成操作后对其进行处理。


哇,谢谢你们的快速回复!我将替换所有的projdatacontext代码,使用“using”方法而不是创建一个新实例并等待其Dispose方法被调用。再次感谢您的帮助。 - o-logn
1
值得注意的是,尽管IDisposable在Linq to SQL中得到了实现,但Linq to SQL的设计者明确指出DataContext在大多数情况下不需要被处理。请参见https://dev59.com/-HRA5IYBdhLWcg3wzhNY#821595。 - Robert Harvey
@o-logn: 那是我的理解。 - Robert Harvey
1
@casperOne:Dispose方法会释放provider成员,并将servicestablesloadOptions成员设置为null。在SqlProvider中的Dispose方法(由DataContext Dispose方法调用)会关闭connection成员,并将其他一些成员设置为null。因此,我不会说它什么都没做。 - Robert Harvey
@casparOne 和 @Robert Harvey:我赞同 casparOne 的论点,并相应地编辑了帖子。 - AxelEckenberger
显示剩余7条评论

2
从实现的角度来看,不需要担心查询问题。然而,这并不是由于查询原因,而是由于 DataContext本身的管理。
DataContext类实现了 IDisposable接口,因此在完成后应该调用DataContext实现上的Dispose方法。
现在,众所周知,在DataContext实例上调用Dispose什么也不做,因此在技术上并不需要。
不幸的是,这也是非常糟糕的做法。您应该始终根据合同编写代码,而不是根据实现。因为DataContext实现了IDisposable,所以应该关闭它,即使您知道它什么也不会做,因为在未来的实现中可能会完全更改。
此外,如果您切换到另一个LINQ提供程序,比如LINQ-to-Entities,那么在完成后您必须调用Dispose,因为 ObjectContext实例(也实现IDisposable)中的数据库连接的生命周期非常不同,而对Dispose的调用会对这些数据库连接产生影响。
话虽如此,您有更大的问题。如果您共享一个DataContext,则有跟踪太多对象的风险。除非您将ObjectTrackingEnabled属性设置为false,否则DataContext将跟踪通过它选择的每个对象。如果您在应用程序的生命周期内没有执行更新操作(甚至如果您执行了更新操作),在共享的DataContext上进行对象跟踪的资源数量可能会变得相当可观。
使用其他数据库技术(例如System.Data.SqlClient命名空间中的)开发的规则仍然适用。
总的来说,像这样共享数据访问资源是一个坏主意。
你应该创建你的资源来访问数据库,执行操作,完成后再释放它们。

谢谢您的帖子。我发布的代码基本上是我在DAL中实现所有方法的方式。如果我像代码中那样为每个方法创建一个新实例,我是否仍然共享DataContext? - o-logn
@o-logn:不,如果您在需要时创建一个新实例(比如在using语句中,每次操作都创建和释放它),那么这将符合上述“根据契约编码”的原则,也是我认为使用DataContext实例的正确方式。 - casperOne
啊,太放心了。本来以为要进行一次大规模的重新编码呢 :). 谢谢! - o-logn

1

使用 Linq-To-SQL 时,通常不需要特别关注上下文对象(例如您示例中的 db)中包含的连接的打开和关闭。唯一需要这样做的情况是,如果您通过上下文对象发送直接 SQL 调用而不是使用 Linq,则必须这样做。

使用 L2S 时,通常希望尽快创建上下文对象、执行工作单元,然后处理对象。您的代码示例看起来很好。


0

我认为使用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;
    }
}

0

数据库连接将在您的db对象不再存在(已释放)或明确关闭后立即关闭。在您的示例中,它将被垃圾回收(早晚)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接