2

@usr和我在另一个问题上存在分歧,即 .NET 是否会清除已空闲但仍保持引用的打开连接。

根据文档,我坚持认为,如果物理连接在一段时间内处于空闲状态,那么即使SQLConnection对象引用保持不变,它也会在一段时间后被回收。

usr 声称这不会发生,它只回收不再具有引用的连接。他的断言将使连接池变得不可靠,并且会对事务造成严重破坏。

我承认,文档对持有参考的问题含糊不清。

我正在寻找对此的权威答案,而不仅仅是猜测。要么有人实验并证明了这两种情况,要么有人了解内部运作。

那么是哪一个呢?

编辑:

我认为这里的混淆在于“封闭”的术语。情况似乎是,文档将关闭物理连接称为从池中“删除”连接。而“关闭”是指将打开的物理连接释放回池中以供重用。

打开的连接仍然可以中止,但是如果客户端应用程序仍将其保持为打开状态(即客户端应用程序尚未在中止的连接上调用关闭),池化程序是否将其标记为无效,但不确定它是否真的很重要,除了作为池计数的一部分。

4

3 回答 3

2

我可以 100% 肯定地告诉您,连接在释放之前不会返回到池中。我有一个会话创建一个临时表,并在等待用户输入时将其挂起。用户在 6 分钟后返回,按下一个按钮,它继续使用相同的SPID,并且临时表的生活继续进行。

应用逻辑,这是有道理的,因为你能想象如果仅仅因为你已经闲置了 X 分钟就失去了 SPID 会造成多大的破坏吗?您是否应该继续使用命令“ping”SQL Server 以使其保持活动状态?(这将是疯狂的


您似乎混淆了两个概念。当连接关闭时,它会返回到池中。如果超出范围,则隐式关闭 -> 返回池。对“空闲”的引用是指池中的连接何时空闲,而不是当它被主动引用且未关闭时。持有的连接甚至不在池中,无法进行任何类型的清理。从池中释放资源是有道理的,因为一个网络应用程序可以轻松地爆发到 100 个连接,然后在接下来的几个月里保持大约 20 个左右的活动并发连接。

于 2012-09-30T19:45:37.783 回答
1

.NET 是否会清除已空闲的打开连接,但仍保持持有的引用

“持有的参考”在这里无关紧要,重点是“开放”。要正确回收连接,您需要Dispose()Close()它。

于 2012-09-30T19:49:19.883 回答
0

我刚刚运行了以下程序:

        var conn = new SqlConnection("...");
        conn.Open();
        conn.ExecuteNonQuery("select null");
        Thread.Sleep(TimeSpan.FromMinutes(11));
        conn.ExecuteNonQuery("select null");

它成功运行(使用自定义辅助方法,因此您无法直接运行它)。

这当然不能证明任何事情(只有在它没有正确运行的情况下)。反射器显示池在 6.5 分钟后第一次清理,此后每 30 秒清理一次:

private Timer CreatePruningTimer()
{
    return new Timer(new TimerCallback(this.PruneConnectionPoolGroups), null, 240000, 30000);
}

所以测试应该已经暴露了问题。

现在,文档中的句子并不是特别清楚。它没有提到 GC 甚至对象引用(在你的问题中你说它有,但它没有)。

连接池程序会定期扫描连接池以查找未通过 Close 或 Dispose 关闭的未使用连接,并回收它找到的那些。如果您的应用程序没有显式关闭或释放其连接,连接池可能需要很长时间才能回收它们,因此最好确保您在连接中显式调用 Close 和 Dispose。

我不相信它。用贝叶斯术语来说,Microsoft 文档是强有力的证据,但如果有强有力的反证,人们可能会得出相反的结论。

我有以下证据表明打开的连接不会无缘无故关闭:

  1. 这将注入无法预防的随机故障(仅通过重试)
  2. 它会中止正常的交易
  3. 这将使长时间运行的交易变得不可能
  4. 我看不出为什么会出现这种行为的原因
  5. 文档中的句子可以按以下方式解释:池定期返回尚未关闭但其相应 SqlConnection 对象已被 GC 处理的连接(通过使用 Wea​​kReference 或其他方式检测)。我猜微软文档作者的意思是,或者不理解这个问题(似是而非!)
  6. 测试没有证明问题
  7. SSMS 如何运行长达一小时的查询?SSMS 应受到同样的限制
于 2012-09-30T19:47:34.750 回答