引发异常时,确保关闭SQL连接的正确方法是什么?
我经常使用看起来像这样的模式。我想知道这是否还行,或者是否有我没有在此处应用的最佳实践。
我特别想知道;在引发异常的情况下,我在finally块中具有的代码是否足以确保正确关闭连接?
public class SomeDataClass : IDisposable { private SqlConnection _conn; //constructors and methods private DoSomethingWithTheSqlConnection() { //some code excluded for brevity try { using (SqlCommand cmd = new SqlCommand(SqlQuery.CountSomething, _SqlConnection)) { _SqlConnection.Open(); countOfSomething = Convert.ToInt32(cmd.ExecuteScalar()); } } finally { //is this the best way? if (_SqlConnection.State == ConnectionState.Closed) _SqlConnection.Close(); } //some code excluded for brevity } public Dispose() { _conn.Dispose(); } }
解决方案
将数据库处理代码包装在"使用"中
using (SqlConnection conn = new SqlConnection (...)) { // Whatever happens in here, the connection is // disposed of (closed) at the end. }
由于我们还是在使用IDisposables。我们可以使用'using'关键字,该关键字基本上等效于在finally块中调用dispose,但看起来更好。
我猜测" _SqlConnection.State == ConnectionState.Closed"的意思是!=。
这肯定会起作用。我认为将连接对象本身包含在using语句中是更常见的做法,但是如果我们出于某种原因想要重用同一连接对象,那么拥有的东西就很好了。
不过,我们绝对应该更改的一件事是Dispose()方法。我们不应在处理中引用连接对象,因为它可能已在此时完成。我们应该改用建议的"处置"模式。
我可能建议这样做:
class SqlOpener : IDisposable { SqlConnection _connection; public SqlOpener(SqlConnection connection) { _connection = connection; _connection.Open(); } void IDisposable.Dispose() { _connection.Close(); } } public class SomeDataClass : IDisposable { private SqlConnection _conn; //constructors and methods private void DoSomethingWithTheSqlConnection() { //some code excluded for brevity using (SqlCommand cmd = new SqlCommand("some sql query", _conn)) using(new SqlOpener(_conn)) { int countOfSomething = Convert.ToInt32(cmd.ExecuteScalar()); } //some code excluded for brevity } public void Dispose() { _conn.Dispose(); } }
希望能对我们有所帮助:)
如图所示,将连接关闭代码放入"最终"块中。最后,在引发异常之前执行块。使用" using"块也可以,但是我发现显式的" Finally"方法更加清晰。
对于许多开发人员而言,使用语句是旧帽子,但是年轻的开发人员可能不知道这一点。
.Net Framework保留一个连接池是有原因的。相信它! :)
我们不必编写太多代码即可连接数据库并释放连接。
我们可以只使用'using'语句,并放心'IDBConnection.Release()'将为我们关闭连接。
精心设计的"解决方案"往往会导致错误的代码。简单更好。
MSDN文档使这一点很清楚...
- Close方法将回滚任何未决的事务。然后,它释放与连接池的连接,或者如果禁用了连接池,则关闭连接。
我们可能尚未(也不想禁用)禁用连接池,因此在我们调用"关闭"后,池最终将管理连接状态。这可能很重要,因为从数据库服务器端看所有打开的连接时,我们可能会感到困惑。
- 一个应用程序可以调用关闭多次。不会产生异常。
那么,为什么要为封闭测试费心呢?只需调用Close()。
- Close和Dispose在功能上是等效的。
这就是为什么using块导致闭合连接的原因。使用呼叫为我们处理。
- 不要在类的Finalize方法中调用Connection,DataReader或者任何其他托管对象上的Close或者Dispose。
重要的安全提示。谢谢,伊贡。
看到这个问题的答案:
关闭并处置该呼叫哪个?
如果连接寿命是一个单一方法调用,请使用该语言的"使用"功能来确保正确清理连接。虽然" try / finally"块在功能上是相同的,但它需要更多的代码,并且IMO的可读性较差。无需检查连接状态,无论如何都可以调用" Dispose",它将处理清理连接。
如果连接生存期与包含类的生存期相对应,则实现" IDisposable"并在" Dispose"中清理连接。
不需要尝试..最终围绕"使用",使用是尝试..最终