我试图向某人解释为什么 数据库连接 实现 IDisposable,当我意识到我真的不知道“打开连接”的实际含义时。
所以我的问题是 - c# 在打开连接时实际上会做什么?

谢谢。

有帮助吗?

解决方案

实际上有两个类涉及实现连接(实际上更多,但我正在简化)。

其中之一是 IDbConnection 执行 (SQLConnection, NpgsqlConnection, OracleConnection, 等)您在代码中使用的。另一个是程序集内部的“真实”连接对象,对代码不可见。我们将其称为“RealConnection” 目前,尽管它的实际名称因不同的实现而异(例如在Npgsql中,这是我最熟悉实现的情况,该类被称为 NpgsqlConnector).

当您创建您的 IDbConnection, ,它没有 RealConnection. 。任何对数据库执行某些操作的尝试都将失败。当你 Open() 然后会发生以下情况:

  1. 如果启用了池化,并且有一个 RealConnection 在池中,将其从队列中取出并使其成为 RealConnection 为了 IDbConnection.
  2. 如果启用池化,则总数 RealConnection 存在的对象大于最大大小,抛出异常。
  3. 否则创建一个新的 RealConnection. 。初始化它,这将涉及打开某种网络连接(例如TCP/IP)或文件句柄(对于 Access 等),通过数据库的握手协议(因数据库类型而异)并授权连接。这然后就变成了 RealConnection 为了 IDbConnection.

进行的操作 IDbConnection 转化为运营 RealConnection 在其网络连接(或其他)上执行操作。结果转化为对象实现 IDataReader 等等,以便为您的编程提供一致的接口。

如果一个 IDataReader 创建于 CommandBehavior.CloseConnection, ,那么该数据读取器就获得了“所有权” RealConnection.

你打电话时 Close() 然后发生以下情况之一:

  1. 如果是池化,并且池未满,则该对象将被放入队列中以供后续操作使用。
  2. 否则 RealConnection 将执行任何协议定义的过程来结束连接(向数据库发出连接将关闭的信号)并关闭网络连接等。然后,该对象可能会超出范围并可用于垃圾回收。

例外情况是如果 CommandBehavior.CloseConnection 情况发生了,在这种情况下是 Close() 或者 Dispose() 被召唤于 IDataReader 会触发这个。

如果你打电话 Dispose() 然后同样的事情发生 Close(). 。不同之处在于 Dispose() 被认为是“清理”并且可以与 using, , 尽管 Close() 可能会在生命中期使用,然后是以后的 Open().

由于使用了 RealConnection 对象以及它们被池化的事实,打开和关闭连接从相对较重变为相对较轻。因此,重要的不是长时间保持连接打开以避免打开它们的开销,而是保持连接打开的时间尽可能短,因为 RealConnection 为您处理开销,并且您使用它们的速度越快,池连接在用户之间共享的效率就越高。

另请注意,这是可以的 Dispose() 一个 IDbConnection 你已经打电话过 Close() on (这是一条规则,调用应该总是安全的 Dispose(), ,无论处于什么状态,实际上即使它已经被调用)。因此,如果您手动调用 Close() 连接仍然很好 using 阻止,以捕获在调用之前发生异常的情况 Close(). 。唯一的例外是您实际上希望连接保持打开状态的情况;假设您要退货 IDataReader 创建于 CommandBehavior.CloseConnection, ,在这种情况下,您不会处置 IDbConnection, , 但 处置读者。

如果您未能释放连接,则 RealConnection 不会返回池中重新使用,或执行其关闭程序。要么池将达到其限制,要么底层连接的数量将增加到损害性能并阻止创建更多连接的程度。最终决赛于 RealConnection 可能会被调用并导致修复,但最终确定只会减少损害并且不能依赖。(这 IDbConnection 不需要终结器,因为它是 RealConnection 持有非托管资源和/或需要关闭)。

还可以合理地假设,对于实施该法案,还存在一些其他独特的处置要求。 IDbConnection 除此之外,即使分析上述内容使您相信没有必要(例外情况是 CommandBehavior.CloseConnection 将所有处置负担转移给 IDataReader, ,但处理该读者也同样重要)。

其他提示

好问题。

根据我对 SQL 连接“底层”工作的了解(有些有限),涉及许多步骤,例如:

引擎盖下的步骤

  1. 打开物理套接字/管道(使用给定的驱动程序,例如 ODBC)
  2. 与 SQL Server 握手
  3. 协商的连接字符串/凭据
  4. 交易范围

更不用说连接池了,我相信涉及某种算法(如果连接字符串与现有池匹配,则将连接添加到池中,否则创建新连接)

I一次性

对于 SQL 连接,我们实现了 IDisposable,以便当我们调用 dispose(通过 using 指令或显式)时,它将连接放回到连接池中。这与普通的旧 sqlConnection.Close() 形成鲜明对比 - 因为它所做的只是暂时关闭它,但保留该连接以供以后使用。

根据我的理解, .Close() 关闭与数据库的连接,而 .Dispose() 调用 .Close() ,并且 然后 释放非托管资源。

记住这些要点,至少实现 IDisposable 是一个很好的做法。

添加到上述...的关键答案是使得在“打开连接”资源可被分配,将需要超过标准垃圾收集以回收,即,打开插座/管/ somekind的IPC的。的Dispose()方法清除这些起来。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top