SQL Server连接池未检测到已关闭的连接?

时间:2010-01-28 11:14:35

标签: .net sql-server ado.net connection-pooling

多年来,我在连接到SQL服务器的所有Web应用程序上遇到了非常奇怪的问题。

问题在于,如果数据库服务器出现问题(服务器重启或其他问题),de web app就会在此时停止工作,即使数据库服务器处于活动状态且之后也很好。

每个ADO.NET操作(ExecuteNonQuery,CreateReader,BeginTransaction,...)都会因 InvalidOperationException 而失败:“无效操作。连接已关闭 ”。似乎对 SqlConnection.Open()的调用从应用程序池中检索了一个已关闭的连接!

根据文档,连接池应该自动从连接池中删除断开的连接,但是显然关闭连接不被视为“切断”,因此调用 SqlConnection.Open()愉快地返回一个已关闭的连接,假设它是打开的,而不检查它。

我目前的解决方法是在打开连接后立即检查连接状态:

using (SqlConnection connection = new SqlConnection( connectionString ))
{
   connection.Open();

   if (connection.State != ConnectionState.Open)
   {
      SqlConnection.ClearAllPools();

      connection.Open();
   }

   // ...
}

这种解决方法似乎现在有效,但我觉得这样做并不舒服。

所以我的问题是:

  1. 为什么 SqlConnection.Open()从连接池返回已关闭的连接?
  2. 我的解决方法有效吗?
  3. 有没有更好的方法来解决这个问题?

2 个答案:

答案 0 :(得分:12)

我之前对连接池进行了一些类似的研究,原因略有不同,但希望会有所帮助。我找到的是:

  1. 即使您在代码中关闭连接,它也会返回到池中而实际上没有关闭连接 - 准备好继续使用。
  2. 如果该连接被切断(即SQL Server重新启动),当从池返回连接以供另一个调用者使用并且该调用者对其执行.Open时,不会出错 at数据库服务器仍然关闭时的那一点。这是连接池性能优势的一部分,因为它实际上并没有回到数据库服务器进行连接。
  3. 当您实际尝试对连接执行命令(例如ExecuteNonQuery)时,它实际上是在抛出异常
  4. 连接会自动从池中删除,我的发现是这通常发生在上次使用后的几分钟内。因此,它可能是一个计时问题 - 它们正在被清除,但是在尝试再次重用连接之前不会这样。

    这些是我当时看到的一些文章:
    Sql Server Google Group
    Using Connection Pooling in ASP.NET

    修改
    这种糟糕的连接永远存在于池中听起来很奇怪 - 你确定它确实存在,它不只是多个不良连接吗?如果您确定,那么听起来您的代码中没有正确释放这些连接。 This是我刚才读过的另一篇非常好的文章,它说(引用):

      

    自动刷新连接

         

    如果合并的连接仍然存在   “封闭但可重复使用”的状态   4到8分钟之间(一个间隔   随机选择)连接   汇集机制关闭物理   连接并丢弃池   连接。这是除非数量   其余的连接更大   比最小连接   为池配置(默认值   是0)。请注意,连接必须   已被申请关闭   (然后释放回游泳池)   它可以自动化   发布。如果你不关闭   代码中的连接或孤立的   连接对象,池   机制什么都不做。不在这里   没有ConnectionString参数   更改超时值。

答案 1 :(得分:2)

我们在使用ADO的C ++中看到了同样的问题。几年前,在使用Microsoft支持后,我们还在代码中实现了类似的重试逻辑,并重置了解决问题的连接池。

如果有更好的解决方法,Microsoft支持人员要么不知道,要么不共享(当时无论如何)。