.NET SqlConnection类,连接池和重新连接逻辑

时间:2009-06-29 14:20:53

标签: c# .net sql-server connection-pooling

我们有一些客户端代码,它使用.NET中的SqlConnection类与SQLServer数据库通信。它会间歇性地失败并出现此错误:

“ExecuteReader需要一个开放且可用的连接。连接的当前状态为已关闭”

“临时”解决方案是重启过程,之后一切正常 - 但是,这显然不能令人满意。

代码保留了SqlConnection实例的缓存,每个数据库都有一个缓存。

我们想重新编写代码,但在此之前,我需要了解一些事情:

我的第一个问题是:重复连接和断开SqlConnection对象是否效率低下,或者底层库是否代表我们执行连接池?

// Is this bad/inefficient?
for(many-times)
{
    using(SQLConnection conn = new SQLConnection(connectionString))
    {
        // do stuff with conn
    }
}

因为我们的代码执行上述操作,所以问题的可能原因似乎是在连接的“生命周期”期间底层SQLServer数据库发生了某些事情,导致连接封闭...

如果事实证明“缓存”SqlConnection对象是值得的,那么建议的方法是处理所有可以通过“重新连接”到数据库来解决的错误。我在谈论的场景如下:

  • 数据库脱机并重新联机,但客户端进程在发生这种情况时没有打开的交易
  • 数据库已“断开连接”,然后“重新连接”

我注意到SqlConnection上有一个“State”属性...是否有适当的方法来查询?

最后,我有一个测试SQLServer实例设置了完全访问权限:我怎样才能再现确切的错误“ExecuteReader需要一个开放且可用的连接。连接的当前状态是关闭的”

3 个答案:

答案 0 :(得分:20)

不,创建大量SqlConnection个对象并在完成后关闭每个对象并不低效。这是正确的做法。让.NET框架连接池完成它的工作 - 不要试图自己做。您无需执行任何特定于启用连接池的任何操作(尽管您可以通过在连接字符串中设置Pooling=false来禁用它。)

如果您尝试自己缓存连接,可能会出现许多问题。只说不:)

答案 1 :(得分:2)

您应该在连接字符串上启用connection pooling。在这种情况下,运行时会在关闭它们时将您的连接添加回“池”,而不是真正取消连接。当从池中取出“新”连接时,它将被重置(即调用sp_reset_connection),然后作为全新的连接呈现给您的应用程序。池正在透明地处理这种情况,就像在池中空闲时关闭连接一样。

从头开始创建新连接的成本非常高,因为身份验证需要在客户端和服务器之间进行多次往返(取决于身份验证方法和SSL设置,在最佳情况下可以是1次往返,而在更糟糕的情况下可以是10次)。

要回答您的问题,连接会在状态发生变化时引发OnStateChange事件,但如果您使用池,则不应该关注此事。

答案 2 :(得分:1)

根据我最近的经验,如果您使用此代码:

using(SQLConnection conn = new SQLConnection(connectionString))
{
    // do stuff with conn
}

有错误,并且没有明确关闭连接,它将不会被关闭或重新检入池中。因此,使用catch或finally块来关闭连接