“打开连接”究竟意味着什么?

我试图向某人解释为什么数据库连接实现IDisposable,当我意识到我真的不知道“打开连接”实际意味着什么。
所以我的问题是 – 当c#打开一个连接时,它实际上做了什么?

谢谢。

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

其中之一是您在代码中使用的IDbConnection实现( SQLConnectionNpgsqlConnectionOracleConnection等)。 另一个是程序集内部的“真实”连接对象,对代码不可见。 我们现在称之为“ RealConnection ”,虽然它的实际名称因不同的实现而不同(例如在Npgsql中,我最熟悉的是实现,该类称为NpgsqlConnector )。

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

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

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

如果使用CommandBehavior.CloseConnection创建了IDataReader ,则该datareader将获得RealConnection的“所有权”。

当您调用Close()时,会发生以下某种情况:

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

例外情况是CommandBehavior.CloseConnection情况发生,在这种情况下,在触发此情况的IDataReader上调用Close()Dispose()

如果你调用Dispose()然后按照Close()发生相同的事情。 不同之处在于Dispose()被认为是“清理”并且可以using ,而Close()可能在生命的中间使用,然后是稍后的Open()

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

还要注意, Dispose()你已经调用了Close() Dispose()IDbConnection是可以的(它是一个规则,它应该总是安全地调用Dispose() ,无论状态如何,实际上即使它已被调用)。 因此,如果您手动调用Close() ,那么在using块中建立连接仍然是好的,以捕获在调用Close()之前发生exception的情况。 唯一的例外是你真正希望连接保持开放的地方; 假设您正在返回使用CommandBehavior.CloseConnection创建的IDataReader ,在这种情况下,您不会丢弃IDbConnection ,但丢弃读取器。

如果您未能处置连接,则RealConnection将不会返回池中以供重用,或者执行其关闭过程。 池将达到其限制,或者底层连接的数量将增加到破坏性能的程度并阻止更多的创建。 最终可能会调用RealConnection上的RealConnection器并导致其被修复,但最终确定只会减少损坏并且无法依赖。 ( IDbConnection不需要终结器,因为它是保存非托管资源和/或需要关闭的RealConnection )。

假设除此之外还有一些其他的IDbConnection实现唯一的处理要求,即使分析上述内容导致您认为不必要,也应该将其处理掉(例外情况是CommandBehavior.CloseConnection将所有处理负担传递给IDataReader ,但是配置读取器同样重要。

好问题。

从我对SQL连接的“底层”工作(有点有限的知识),涉及许多步骤,例如:

引擎盖下的步骤

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

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

IDiposable

关于SQL Connections,我们实现了IDisposable,这样当我们调用dispose(通过using指令或表达式)时,它会将连接放回连接池。 这与普通的旧sqlConnection.Close()形成鲜明对比 – 因为所有这一切都暂时关闭它,但保留该连接供以后使用。

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

记住这些要点,至少实现IDisposable是一种好习惯。

添加上面的答案……关键是,在“打开连接”时,可能会分配资源,这将需要超过标准的垃圾收集来恢复,即某些开放的套接字/管道/ IPC。 Dispose()方法清除了这些。