【问题标题】:How to force a SqlConnection to physically close, while using connection pooling?如何在使用连接池时强制 SqlConnection 物理关闭?
【发布时间】:2019-01-28 07:48:48
【问题描述】:

我知道,如果我实例化一个 SqlConnection 对象,我实际上是在从连接池中抓取一个连接。当我调用 Open() 时,它将打开连接。如果我对该 SqlConnection 对象调用 Close() 或 Dispose() 方法,它会返回到连接池。

但是,这并不能真正告诉我它是否真的关闭了,或者我是否仍然与数据库保持活动连接。

如何强制 SqlConnection 在网络级别关闭,或者至少告诉它何时关闭?

示例:

using(SqlConnection conn = new SqlConnection(DBConnString)) {

   conn.Open();
   SqlCommand cmd = conn.CreateCommand();
   ...
   cmd.ExecuteReader(CommandBehavior.CloseConnection);
   ...
}
  • 首次运行:300 毫秒
  • 第二次运行:100 毫秒
  • 第三次运行:100 毫秒
  • 等待很长时间(30 分钟)后:300 毫秒

如果连接真正关闭,第二次和第三次运行也应该是 300 毫秒。但我知道连接并没有真正关闭那些运行(我检查了 SQL Server 的活动监视器)。执行身份验证/等不需要额外的 200 毫秒。

如何强制连接真正关闭?

想法

  • CommandBehavior.CloseConnection 是否有效? (显然不是?)
  • 在连接字符串中设置“Max Pool Size = 0”是否有效? (这将是一个昂贵的解决方案)
  • Dispose() 有效吗?

参考文献

【问题讨论】:

  • 为什么连接真正关闭?性能低下?

标签: c# sql ado.net database-connection connection-pooling


【解决方案1】:

【讨论】:

  • 我正在这样做,但是我的 SQL 连接仍然显示在 sp_who2 中,并且我的 SQL 会话持有的 AppLocks 保持锁定(我打算让它们随着连接而死)。我什至设置了connStrBuilder.Polling = false
【解决方案2】:

Moe Sisko 的回答(电话SqlConnection.ClearPool)是正确的。

有时您需要连接才能真正关闭而不是返回池。例如,我有一个单元测试,它创建一个临时数据库、构建架构、测试一些东西,然后如果测试全部通过,则删除临时数据库。

当连接池处于活动状态时,drop database 命令会失败,因为仍有活动连接。从程序员的角度来看,所有 SQLConnections 都已关闭,但由于池仍保持打开状态,SQL Server 将不允许删除。

关于如何处理连接池的最佳文档是 MSDN 上的 this page on SQL Server Connection Pooling。人们不想完全关闭连接池,因为它可以通过重复打开和关闭来提高性能,但有时您需要在 SQLConnection 上调用“强制关闭”,以便它释放数据库。

这是通过 ClearPool 完成的。如果您在关闭/处置之前致电SqlConnection.ClearPool(connection),当您关闭/处置时,它真的会消失。

【讨论】:

  • 您描述的用例几乎与我所做的完全一样——测试某些数据库访问模式的性能,使用“冷”过程/数据缓存,当然还有连接。
  • 您提供的链接已添加到问题文本中。谢谢。
  • 对我来说同样的场景:-)
  • 您可以通过在关闭连接之前发出use master; 来解决问题(“当连接池处于活动状态时,drop database 命令失败,因为仍有活动连接”) .它不能回答 OP 的问题,但可以解决您的问题。
【解决方案3】:

如果您不想使用连接池,则必须在 SqlConnection.ConnectionString 属性中指定它。例如

"Data Source=MSSQL1;Database=AdventureWorks;Integrated Security=true;Pooling=false;"

释放或关闭SqlConnection 对象只会关闭连接并将其返回到连接池。

【讨论】:

    【解决方案4】:

    通常,您希望连接池完成其工作 - 您不希望连接真正关闭。

    为什么你不希望连接返回池?

    【讨论】:

    • 池中的连接可以持有锁。
    • 我也不确定您指的是哪种锁 - 其底层连接返回到连接池的已处置连接不应参与任何事务或持有与消费代码相关的任何锁.当然,它仍然使用网络端口和一些其他资源 - 但这些资源的获取成本正是为什么释放它们的原因。除非您尝试删除/恢复底层数据库或类似激进的东西,否则这些锁不会有问题。
    • 池中的连接可以防止对数据库的独占访问。
    【解决方案5】:

    我看到您正在使用 .net,但由于这显示在 google 查询中,请允许我给出 java 响应...

    使用实现 Closeable() 的 DataSource 并在 DataSource 上调用 close。 Hikari 支持 Closeable。

    【讨论】:

      【解决方案6】:

      CommandBehavior.CloseConnection 通常因为这个事实而被劝阻——你不能确定连接是否会被关闭。 (我会试着找到一些具体的证据,我是从微弱的回忆中说出来的)。

      Dispose()最可靠的方式,因为它隐式调用Close()

      @Alex 演示的 using 构造只是编写 try-finally 构造的另一种(程序员友好)方式,并添加了对象的隐式 Disposal。

      编辑:(编辑问题后)

      您对连接实际上关闭的担忧对我来说似乎没有根据。连接将简单地返回到池中,以便可以轻松地重用它,而无需进行所有初始化。这并不意味着 Connection 仍然主动连接到 DB。

      【讨论】:

      【解决方案7】:

      罗伯特对SqlConnection.ClearPool(TheSqlConn) 的回答正是我想要的。很高兴知道可以在必要时与池进行交互。

      我的用例是:我们破坏了一个连接,让它回到池中,我们如何检测它被破坏并刷新它,所以下一个用户不会有问题。

      解决方案是:检测到我们刚刚破坏了连接,并将其从池中完全清除,让池中充满新的连接。

      十年来编写 SqlClient.SqlConnection,直到今天我什至从未想过与池进行交互。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-07
        • 1970-01-01
        • 1970-01-01
        • 2018-07-13
        • 2019-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多