5

使用 SqlConnection 时,务必在使用时关闭它 - 通过 .Close() 或将 SqlConnection 置于“使用”中。不幸的是,包括我自己在内的人们往往会忘记这一点,这就是垃圾收集器暂时拯救我的地方,直到我忘记关闭我的连接太多次或使用该应用程序的人数增加。

如果可能的话,我想知道如何检测垃圾收集器是否处理了 SqlConnection,因为它认为它不再使用,或者 SqlConnection 是否以正确的方式关闭。

另一种方法可能是继承 SqlConnection 并在其初始化程序上放置一个计时器,并检查在处理类时关闭连接需要多长时间。我真的不喜欢计时器,但这个想法是在写这篇文章的时候出现的。

也许有第三种甚至更聪明的方法来解决这一切......你会推荐什么?

4

6 回答 6

4

由于 SqlConnection 是密封的,您将无法从它继承。(而且我认为这样做不是一个好主意——如果可能的话,您可能应该在 Dispose(false) 中添加您的代码,因为这是终结器所调用的)。

最好使用静态代码分析工具来检测此类问题,该工具能够检测代码中您忘记处理连接的所有位置。Visual Studio 中内置了一个,或者您可以使用FxCop

为了帮助您不要忘记处理连接,最好:

  • 将所有数据库连接代码保存在一层/程序集/模块中,因此不会分散在项目中。
  • 具有执行 SQL 命令并返回结果的实用方法;因此,您创建的 SQLConnection 位置不会超出您的需要。
  • 请记住使用C# using 构造
于 2010-06-29T18:25:23.253 回答
2

一条经验法则说:“如果你必须考虑垃圾收集器,你可能做错了什么。” (当然,还有其他的大拇指……)

在我看来,确保连接被明确或通过usingfinally块关闭是最好的途径。

显然,您已经了解这些技术……因此,您可能只需要一次性的代码和可能的重构。

于 2010-06-29T18:23:54.060 回答
1

如果您的应用程序使用 SQL 连接池(默认),则无关紧要,因为连接会被重复使用,并且在您调用 .Close() 或离开 using() {} 块时不会关闭。

http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx

为了回答你的问题,我不相信有一个 GC 收集事件,但是如果有没有关系,因为你永远不会知道 GC 是否选择在该收集过程中回收你的对象(并非所有对象都被清理,因为代算法)。

我还将避免尝试使用计时器和“检查”,因为您可能会持有对该对象的引用并防止它被处置。

于 2010-06-29T18:25:52.677 回答
1

我对垃圾收集器不是很熟悉,不知道是否有直接的方法来获取信息,但我的第一个想法是以下一个。

只需创建对虚拟对象的弱引用。如果您稍后查看弱引用并且该对象不再存在,您可能会假设发生了垃圾收集。

(此答案仅适用于检测垃圾收集器运行。我完全忽略了这样做的原因 - 有更好的策略来处理资源泄漏。)

于 2010-06-29T18:27:43.973 回答
0

如果您忘记处置,该对象将被最终确定。无法控制发生这种情况的时间,您也无法知道对象是否已完成。为了最终确定对象,必须创建一个单独的线程,因此它会减慢您的应用程序的速度。这就是你想要处理的原因。在实现 IDisposable 的框架中的所有类中,都会调用 GC.SuppressFinalize,因此对象没有最终确定。

您无法控制这种行为。如果您的对象不再使用,它​​将自动被收集。要阻止这种情况,你所能做的就是调用 GC.SuppressFinalize,但我不建议这样做,因为如果你忘记了,你会终生被搞砸。

不过,您可以创建一个包装类(不是子类),在您的代码中使用它提供一些始终调用 Dispose 的简单方法。否则,只需检查非常好。

于 2010-06-29T18:24:35.133 回答
0

首先,如果您甚至考虑使用 GC,那么您在某个地方就会遇到严重的问题。我建议确保您的代码调用 Close 的最佳方法是使用诸如mocking之类的技术对您的代码进行单元测试。如果您的单元测试表明调用了 Close,那么您的代码是正确的,并且您不必做任何不必要的危险,例如使用垃圾收集器。

其次,如果您仍然坚持走运行时检查路线,那么您唯一应该考虑做的就是挂钩. 例如,如果 ConnectionState 从 Open 更改为 Closed,则会触发。StateChangeSqlConnection

于 2010-06-29T18:27:43.197 回答