连接池可能存在切断的连接

Fil*_*vić 6 .net c# ado.net connection-pooling sqlconnection

我有多个线程访问同一个数据库(具有相同的连接字符串).每个帖子:

  • 使用相同的连接字符串创建自己的SqlConnection实例
  • 使用下面的代码在需要时打开它自己的连接实例

        try
        {
            wasOpened = connection.State == ConnectionState.Open;
    
            if (connection.State == ConnectionState.Closed)
            {
                connection.Open();
            }
        }
        catch (Exception ex)
        {
            throw new Exception(string.Format("Connection to data source {0} can not be established! Reason: {1} - complete stack {2}",
                                              connection.Database, ex.Message, ex.StackTrace == null ? "NULL" : ex.StackTrace.ToString()));
        }
    
    Run Code Online (Sandbox Code Playgroud)

到目前为止,我们已在2台服务器上测试了此代码,并且有一台服务器有时会在SqlConnection.Open方法中抛出异常.这是我们从catch块获得的异常消息:

无法建立与数据源xyz的连接!原因:操作无效.连接已关闭. - 完整的堆栈

在System.Data.SqlClient.SqlConnection.OpenConnection()
处于System.Data.SqlClient.SqlConnection.OpenConnection()
处于System.Data.SqlClient.SqlConnection.Open()

检查SqlConnection.GetOpenConnection方法显示innerConnection为null:

internal SqlInternalConnection GetOpenConnection()
{
    SqlInternalConnection innerConnection = this.InnerConnection as SqlInternalConnection;
    if (innerConnection == null)
    {
        throw ADP.ClosedConnectionError();
    }
    return innerConnection;
}
Run Code Online (Sandbox Code Playgroud)

我不清楚:为什么连接池有时会给我切断的连接(innerConnection == null)?

编辑#1:代码中没有静态属性 - 我们总是在适当时关闭连接,在我们的Close方法中使用wasOpened并且意味着:如果在调用Open时已经打开了连接,只需在关闭时保持打开,否则关闭它.但是,这与此问题中描述的问题无关(innerConnection == null).

编辑#2:服务器:SQL Server 2008 R2,Windows Server 2003.客户端:Windows Server 2003(代码在SSIS包自定义组件中运行).连接字符串:Data Source=server_name;Initial Catalog=db_name;Integrated Security=SSPI;Application Name=app_name

Tim*_*ter 5

首先,仔细阅读:SQL Server连接池(ADO.NET)

我会为你引用最重要的部分(我认为):

为每个唯一连接字符串创建连接池.创建池时,会创建多个连接对象并将其添加到池中,以满足最小池大小要求.根据需要将连接添加到池中,直到指定的最大池大小(默认值为100).关闭或处置时,连接会释放回池中.

当请求SqlConnection对象时,如果可用的连接可用,则从池中获取它.要使用,连接必须是未使用的,具有匹配的事务上下文或与任何事务上下文无关,并且具有到服务器的有效链接.

连接池通过在连接释放回池中时重新分配连接来满足连接请求.如果已达到最大池大小且没有可用的可用连接,则请求将排队.然后,pooler尝试回收任何连接,直到达到超时(默认为15秒).如果在连接超时之前,pooler无法满足请求,则抛出异常.

我们强烈建议您在使用完毕后始终关闭连接,以便将连接返回到池中.您可以使用Connection对象的Close或Dispose方法,或打开C#中using语句内的所有连接,或Visual Basic中的Using语句来执行此操作.未显式关闭的连接可能不会添加或返回到池中.有关更多信息,请参阅using Statement(C#Reference)

简而言之:一旦你完成它们(fe via using-statement),不要在连接池的范围内偷猎并关闭连接.

既然你不想把你的DB-Class扔进垃圾桶,我建议要么增加最大池大小和/或超时,要么禁用池,看看会发生什么.

<add name="theConnectionString" connectionString="Data Source=(local);
     Database=AdventureWorks; Integrated Security=SSPI; 
     Max Pool Size=200; Pooling=True; Timout=60" />
Run Code Online (Sandbox Code Playgroud)

您还应该尝试捕获此特定错误并清除所有连接池:

System.Data.SqlClient.SqlConnection.ClearAllPools();
Run Code Online (Sandbox Code Playgroud)

或者看看这些看起来很有希望的问题:


Bry*_*sby 2

我有多个线程访问同一数据库(具有相同的连接字符串)。每个线程:

  1. 使用相同的连接字符串创建它自己的 SqlConnection 实例
  2. 使用下面的代码在需要时打开它自己的连接实例

如果您遇到随机出现的问题,在您的情况下,根据您显示的代码,您可能会遇到:

  1. 服务器上的连接池有问题
  2. 代码中某处的竞争条件

话虽这么说...

您应该将您的内容包含在声明SqlConnectionusing。这样,当您的代码或线程完成连接时,连接将被关闭。

using (SqlConnection connection = new SqlConnection(connectionString))
{
   //... stuff
}
Run Code Online (Sandbox Code Playgroud)

这样,连接就可以保证调用该Dispose()方法(Close()无论如何都会在内部调用)。这样,如果连接正在使用(可能正在使用),则可以将其返回到池中。