使用ADO.NET管理数据库连接

时间:2008-12-05 04:54:01

标签: .net ado.net timeout

我们有一个基于ADO.NET构建的应用程序。我们遵循一些简单的最佳实践,允许我们使用连接池。例如,使用数据库的代码块可能如下所示:

using( DbConnection dbConnection = GetDatabaseConnection() ) {   
    doWork();
}

FWIW,GetDatabaseConnection并没有什么特别之处。它与运行MSSQL Server 2000的数据库建立连接。实际上,它如下所示:

DbConnection GetDatabaseConnection() {
    return GetConnection(MyConnectionString);
}

DbConnection GetConnection(String connectionString)
{
  try {
      SqlConnection dbConnection = new SqlConnection(connectionString);
      dbConnection.Open();
      return dbConnection;
  } catch( InvalidOperationException ex ) {
      handleError(ex);
      throw;
  } catch( DbException ex ) {
      handleError(ex);
  }
}

因此,我们的连接在块范围的末尾被处理掉。但是,当我们开始测试应用程序时,我们遇到了一些小故障。我们发现我们的应用程序是非常突发的,这意味着它有时会变得非常健谈,然后会沉默一段时间。结果是我们可以同时拥有多个线程以获得连接。

所以想象你有10个主题。一批工作(请不要试图改写一批工作)到达并分成几个线程。然后每个线程都尝试获取连接和繁荣,我遇到了InvalidOperationException。我已经调整了ConnectTimeout,所有这一切都延长了时间,直到我遇到异常突发。一旦我通过“结束”阶段,应用程序就可以了。然后它再次停顿,连接“消失”并且过程再次开始。

我也尝试过调整LoadBalanceTimeout,但异常继续存在。你们之前有没有见过这个问题?任何想法......我会抛出一些自己的想法。

  • 不断保持一些连接“热”
  • 尝试再次打开连接,直到某些尝试次数
  • 实施我自己的连接池(bleah,对重新发明轮子不感兴趣)

编辑:

我读过的大多数论坛都不鼓励增加连接池大小。默认情况下,连接池的上限为50个连接(这已经足够了 - 如果我必须增加它,那么其他地方的根本错误)。我注意到当ConnectTimeout为低时,会发生InvalidOperationException。就好像连接的旋转太长而挂起的连接都超时了。

MARS肯定是一个选项...... InvalidOperationException.Message的文本是:

超时已过期。从池中获取连接之前经过的超时时间。这可能是因为所有池连接都在使用中并且达到了最大池大小。

4 个答案:

答案 0 :(得分:2)

来自MSDN(http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx):

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

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

翻译:检查您的交易环境...如果您的联盟大小为10个连接,并且在不同的交易中创建了10个连接,那么您就搞砸了。

请注意,只有在尝试与服务器通信后才能检测到切断的连接 。如果找到不再连接到服务器的连接,则将其标记为无效。仅当连接池关闭或回收时,才会从连接池中删除无效连接 如果已消失的服务器存在连接,则即使连接池未检测到已断开连接并将其标记为无效,也可以从池中提取此连接。这种情况是因为检查连接仍然有效的开销将通过导致另一次往返服务器的发生来消除使用pooler的好处。发生这种情况时,第一次尝试使用连接将检测到连接已被切断,并引发异常

翻译:您真的不能依赖连接吗?这篇文章并没有真正解释如何处理这个......

您可以尝试使用ClearAllPools和ClearPool手动清除游泳池,但这对我来说听起来像是一个创可贴,让我感到畏缩。

文章还讨论了安全背景,说:
通过调用sp_setapprole系统存储过程激活SQL Server应用程序角色后,无法重置该连接的安全上下文。但是,如果启用了池,则会将连接返回到池,并且在重用池化连接时会发生错误。

我开始想知道为什么我使用连接池......

最后:
由于集成安全性造成的池碎片
根据连接字符串和用户标识共享连接。因此,如果在网站上使用基本身份验证或Windows身份验证以及集成安全登录,则每个用户可以获得一个池。虽然这可以提高单个用户的后续数据库请求的性能,但该用户无法利用其他用户建立的连接。它还会导致每个用户至少与数据库服务器建立一个连接。

因此,如果您在Web应用程序上使用集成安全性,则可以填写连接池,如果您有足够的用户。

在不了解您的应用程序的更多细节的情况下,很难放大可能绊倒您的内容,但希望这能为您提供一些想法。

HTH

答案 1 :(得分:0)

您可以尝试将“最大泳池尺寸”设置得更高。您也可以尝试在连接上显式调用“关闭”。

答案 2 :(得分:0)

问题1:你的GetDatabaseConnection()方法是否分离出一个新线程来生成数据库连接并将其返回给主线程......或者是多个线程试图访问这个方法而不是方法......或者是这个方法是一个只从池中获取连接的共享/静态方法吗?

问题2:您的数据库服务器是什么品牌和型号? SQL Server?甲骨文? PostgreSQL的?

问题3:您是否要求在不同的连接上完成所有工作,或者是否可以在一个连接上完成,是否足够?如果是SQL Server,那么MARS允许单个连接上的多个记录集可能会有所帮助,但可能对您的应用程序不可行。

问题4:返回的异常中的细节是什么?

只是想清楚了解您的应用程序架构是如何工作的......

(P.S。有没有人知道我如何将“答案”标记为“不是答案,而是要求进一步澄清”......即对于这个“答案”)

答案 3 :(得分:0)

根据MSDN,如果您尚未指定数据源或服务器,或者连接已经打开,则SqlConnection.Open将抛出InvalidOperationException。

您确定在“doWork”方法中没有对SqlConnection.Open的任何调用吗?

此外,您在GetConnection方法中的代码吞下DbException。