8

我们有一些客户端代码使用 .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 上有一个“状态”属性......有没有合适的方法来查询它?

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

4

3 回答 3

20

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

如果您尝试自己缓存连接,有很多事情可能会出错。拒绝吧 :)

于 2009-06-29T14:22:59.570 回答
2

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

“从头开始”创建新连接的成本很高,因为身份验证需要客户端和服务器之间的多次往返(取决于身份验证方法和 SSL 设置,最好的情况下可能是 1 次往返,而更糟的情况下大约是 10 次)。

为了回答您的问题,连接会在状态更改时引发OnStateChange事件,但如果您使用池,则不必关心这一点。

于 2009-06-29T14:29:30.397 回答
1

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

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

有错误,并且不显式关闭连接,它不会被关闭或检回池中。所以使用 catch 或 finally 块来关闭连接

于 2012-01-07T20:04:32.597 回答