我曾试图向某人解释为什么 数据库连接 实现了 IDisposable 接口,但是后来我意识到我其实不知道 "打开一个连接" 具体指什么。
因此我的问题是 - 当 C# 打开一个连接时,它实际上在做什么?
谢谢。
我曾试图向某人解释为什么 数据库连接 实现了 IDisposable 接口,但是后来我意识到我其实不知道 "打开一个连接" 具体指什么。
因此我的问题是 - 当 C# 打开一个连接时,它实际上在做什么?
谢谢。
当您调用Close()
时,会发生以下情况之一:
RealConnection
将执行结束连接的任何协议定义程序(向数据库发出信号表示连接即将关闭)并关闭网络连接等。对象然后可能超出范围并可供垃圾回收。例外情况是如果发生 CommandBehavior.CloseConnection
情况,则触发对 IDataReader
上的 Close()
或 Dispose()
的调用。
如果调用Dispose()
,则与Close()
相同的事情会发生。不同之处在于,Dispose()
被认为是“清理”,可以与using
一起使用,而 Close()
可能在生命周期中间使用,并在稍后跟随 Open()
。
由于使用了RealConnection
对象并且它们被汇聚在一起,因此打开和关闭连接从相对较重的操作变为相对较轻的操作。因此,与其重要的是要保持长时间的连接以避免打开它们的开销,还不如将其保持尽可能短的时间,因为RealConnection
为您处理开销,并且您使用连接越快,汇聚的连接就会更高效地在多个使用之间共享。
Close()
方法关闭了 IDbConnection
连接,在此之后再调用 Dispose()
方法也是可以的(事实上,规则是无论连接处于什么状态,甚至已经调用过 Dispose()
方法,都应该安全地调用它)。因此,如果您手动调用了 Close()
方法,将连接放入 using
块中仍然是一个好习惯,以便在调用 Close()
方法之前发生异常的情况下能够捕获异常。唯一的例外情况是您确实希望连接保持打开状态;例如,您正在返回使用 CommandBehavior.CloseConnection
创建的 IDataReader
,此时您不需要处理 IDbConnection
,但是需要处理读取器。RealConnection
将不会被返回到池中以供重用,也不会经过其关闭过程。池可能会达到限制,或者底层连接的数量会增加到破坏性能并阻止创建更多连接的程度。最终 RealConnection
上的清除程序可能会被调用并解决这个问题,但是清除程序只能减少损坏,不能依赖它。 (IDbConnection
不需要清除程序,因为是 RealConnection
持有未托管的资源和/或需要执行关闭)。IDbConnection
的实现中还存在其他处理要求,并且即使分析上述内容使您认为不需要进行处理,它仍应该被处理(例外情况是使用 CommandBehavior.CloseConnection
将所有处理负担传递给 IDataReader
,但是这时处理读取器同样重要)。很好的问题。
从我对SQL连接的“底层”工作的(有限)了解,涉及到许多步骤,例如:
底层步骤
更不用说连接池了,我认为这里涉及到某种算法(如果连接字符串与已经存在的池中的连接字符串匹配,则将连接添加到池中,否则创建新的连接)。
IDisposable
关于SQL连接,我们实现IDisposable,以便在调用dispose时(通过using指令或显式方式),它将连接放回连接池。这与只是简单的sqlConnection.Close()形成鲜明对比-因为所有这些都只是暂时关闭它,但保留该连接以供以后使用。
据我所知,.Close()会关闭与数据库的连接,而.Dispose()会调用.Close(),然后释放非托管资源。
考虑到这些要点,至少实现IDisposable是个好习惯。
补充以上答案...关键在于“打开连接”时可能会分配资源,这些资源需要比标准垃圾回收更长的时间来恢复,即某种类型的打开套接字/管道/IPC。Dispose()方法可以清理这些资源。