我试图向某人解释为什么数据库连接实施IDisposable,当我意识到我真的不知道“打开连接”实际意味着什么。
所以我的问题是 - 当它打开连接时,c#几乎可以做什么?
谢谢。
答案 0 :(得分:22)
实际上有两个类涉及实现连接(实际上更多,但我正在简化)。
其中之一是您在代码中使用的IDbConnection
实施(SQLConnection
,NpgsqlConnection
,OracleConnection
等)。另一个是程序集内部的“真实”连接对象,对代码不可见。我们现在称之为“RealConnection
”,虽然它的实际名称因实现的不同而不同(例如在Npgsql中,我最熟悉的是实现,该类称为{{1} })。
创建NpgsqlConnector
时,它没有IDbConnection
。任何对数据库执行某些操作的尝试都将失败。当你RealConnection
时,会发生以下情况:
Open()
,请将其解除并使其成为RealConnection
的{{1}}。RealConnection
个对象的总数大于最大大小,则抛出异常。IDbConnection
。初始化它,它将涉及打开某种网络连接(例如TCP / IP)或文件句柄(用于Access之类的东西),通过数据库的协议进行握手(因数据库类型而异)并授权连接。然后,这将变为RealConnection
的{{1}}。 RealConnection
上执行的操作将转变为RealConnection
在其网络连接(或其他)上执行的操作。结果转化为实现IDbConnection
等的对象,以便为您的编程提供一致的界面。
如果使用IDbConnection
创建了RealConnection
,那么该数据加载器将获得IDataReader
的“所有权”。
当您致电IDataReader
时,会发生下列情况之一:
CommandBehavior.CloseConnection
将执行任何协议定义的过程以结束连接(向连接将要关闭的数据库发送信号)并关闭网络连接等。然后,对象可以脱离范围并可用于垃圾收集。例外情况是RealConnection
案例发生,在Close()
上调用RealConnection
或CommandBehavior.CloseConnection
会触发此事件。
如果您致电Close()
,那么根据Dispose()
发生同样的事情。不同之处在于IDataReader
被视为“清理”并且可以与Dispose()
一起使用,而Close()
可能会在生命中期使用,之后是Dispose()
}}
由于using
对象的使用以及它们被合并的事实,打开和关闭连接从相对较重变为相对较轻。因此,长时间保持连接打开以避免打开它们的开销是很重要的,因此尽可能短的时间保持它们的开放变得很重要,因为Close()
为您处理开销,使用它们的速度越快,合并连接在使用之间共享的效率就越高。
另请注意,Open()
RealConnection
您已拨打RealConnection
就可以了(规则是Dispose()
应始终安全的规则,无论什么状态,实际上即使已经被召唤了)。因此,如果您手动调用IDbConnection
,那么在Close()
块中建立连接仍然是好的,以便在调用Dispose()
之前捕获异常发生的情况。唯一的例外是你真正希望连接保持开放的地方;假设您返回使用Close()
创建的using
,在这种情况下,您不会释放Close()
,但执行会处置读者。
如果您未能处理连接,则IDataReader
将不会返回到池中以供重用,或者执行其关闭过程。池将达到其限制,或者底层连接的数量将增加到破坏性能并阻止更多创建。最终CommandBehavior.CloseConnection
上的终结者可以被调用并导致这个被修复,但最终确定只会减少伤害并且不能依赖。 (IDbConnection
不需要终结器,因为它是保存非托管资源和/或需要关闭的RealConnection
。
除此之外,假设除了RealConnection
之外还有其他一些处理要求是独一无二的,即使分析上述情况导致您认为没有必要,也应该将其处理掉(例外情况是当IDbConnection
将所有处置负担传递给RealConnection
时,但处置该读者同样重要。
答案 1 :(得分:4)
好问题。
根据我对SQL连接的“底层”工作的知识(有点有限),涉及许多步骤,例如:
引擎盖下的步骤
更不用说连接池,我相信会涉及某种算法(如果连接字符串与已存在的池匹配,则连接被添加到池中,否则会创建新的连接)
<强> IDiposable 强>
关于SQL Connections,我们实现了IDisposable,这样当我们调用dispose(通过using指令或显式)时,它会将连接放回连接池。这与普通的旧sqlConnection.Close()形成鲜明对比 - 因为所有这一切都暂时关闭它,但保留该连接供以后使用。
根据我的理解,.Close()关闭与数据库的连接,而.Dispose()调用.Close(),然后释放非托管资源。
这些要点,至少是实施IDisposable的好习惯。
答案 2 :(得分:0)
添加上面的答案......关键是,在“打开连接”时,可能会分配资源,这将需要超过标准的垃圾收集来恢复,即某些开放的套接字/管道/ IPC。 Dispose()方法清除它们。