繁体   English   中英

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

[英]Connection pool with possible severed connections

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

  • 使用相同的连接字符串创建自己的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())); } 

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

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

在System.Data.SqlClient.SqlConnection.GetOpenConnection()
在System.Data.SqlClient.SqlConnection.get_Parser()
在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;
}

我不清楚:为什么连接池有时会给我断开的连接(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

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

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

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

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

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

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

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

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

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

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

System.Data.SqlClient.SqlConnection.ClearAllPools();

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

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

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

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

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

所有这一切......

您应该将SqlConnection包装在using语句中。 这样,当您的代码或线程完成后,连接将被关闭。

using (SqlConnection connection = new SqlConnection(connectionString))
{
   //... stuff
}

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

Tim SchmelterBryan Crosby提供的答案在指南,参考资料,最佳实践等方面都非常有价值。 不幸的是,这对我来说还不够,因为我不能在遗留代码中做出重大改变。

解决这个特殊问题的方法是使用相同的锁封装SqlConnection的Open和Close方法。 请注意,它符合我们的情况,可能不适合其他人。

我真的很抱歉我现在无法深入研究这个问题,并找出问题的根源是我们的代码还是连接池不是完全线程安全的。 我知道很可能源代码在我们的代码中。 考虑到这一点,这个答案比真正的解决方案更具解决方法。

在任何人应用此解决方法之前,请阅读其他答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM