未关闭的数据库连接会发生什么?

7

今天早些时候,我在我们的一个项目中发现了一个bug - 数据库连接从未关闭,我的意思是Close()方法从未被调用。然而,当我关闭应用程序时,连接会被关闭(在SQL管理工具中多次检查)。为什么会这样呢?

4个回答

4
当应用程序退出时,连接将关闭。请查阅 SqlConnection's Finalize。来自 MSDN Object.Finalize 文档的说明:
“在应用程序域关闭期间,即使仍然可访问,仍未豁免最终化的对象上自动调用 Finalize。”

如果SqlConnection超出范围,它将不会被关闭。因此,您必须通过调用Close或Dispose来显式关闭连接。这是从msdn上的内容,难道这不意味着如果您不调用Close(),连接可能不会关闭吗? - agnieszka
基本上你可以使用Close、Dispose或者using(){}语句块,就像你本来应该做的那样。当应用程序关闭时,连接也将关闭,这是我在回答中提到的原因。 - RichardOD
如果垃圾回收器决定最终关闭连接,那么它们也会被关闭。 - RichardOD

2

还有一件需要记住的事情是,在 .Net 中,您可以将连接包装在 using 块中,这样会为您关闭和处理连接。因此,如果您已经使用了 using 块,那么缺少显式的 Close() 并不是一件坏事...

// this using block will auto close & dispose your connection...
using (var conn = new SqlConnection(...))
{
    conn.Open();
    // database code here with no explicit close

}

这段话中提到了try/finally块与conn.close的功能等价。许多开发人员忽视了using块——请确保在此情况下您未做同样的事情。如果您重写代码以关闭连接,最好使用Using块包围所有数据库对象(连接、命令、读取器),以确保它们在using块的范围之外时关闭和处理。我强烈建议您将这些内容编写到代码中,而不仅仅是在需要时使用conn.Close()。

是的,这就是我做事的方式。如果你使用FXCop,你永远不会遇到问题,因为它会警告你没有调用Dispose方法。 - RichardOD
没有使用块,我知道它们。 - agnieszka
这不是问题的答案。 - agnieszka
@agnieszka - 你会惊讶地发现有多少人忽视了这一点,并把在using块中缺少Close当作一个bug。我只是指出了很多人忽视的事实。当你给我投了反对票时,我还在研究你问题的其他部分的答案,所以非常感谢你... - Scott Ivey

1

SQL 连接创建的成本很高,ADO.NET 使用一种称为连接池的技术来重用它们。

引自 MSDN 的一句话:

强烈建议您在使用完毕后始终关闭连接,以便将其返回到连接池并重用。

如果已达到最大池大小且没有可用连接,则请求将被排队。然后池管理器尝试回收任何连接,直到达到超时时间(默认为 15 秒)。如果池管理器在连接超时之前无法满足请求,则会抛出异常。


1
实际上,由于连接池的存在,SQL连接永远不会被真正关闭 - 它只是返回到池中以便在调用Close时重新使用。当应用程序域被销毁即退出应用程序时,它将被关闭。因此,如果您从未调用Close,则连接不会被重用,一旦池耗尽,您将收到异常。 - Darin Dimitrov
@darin- 从未真正关闭是不正确的。在一定时间内没有活动后,连接将被关闭,但这只是挑剔。 - RichardOD
1
@RichardOD,我不会说这是挑剔。实际上,我并不知道这个事实。非常感谢您的精确解释。 - Darin Dimitrov

1

当您正常退出应用程序时,我期望 finalizers 能够运行。如果连接仍然打开,它们将关闭该连接。 但是不要依赖此功能:在应用程序正常操作中,finalizers 运行可能需要一些时间,因此您将保持过多的打开连接。

当应用程序崩溃时,可能 finalizer 不会运行,从而使连接超出应用程序生命周期而保持打开状态。


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