关闭SQLDataReaders – 如何判断它们是否已关闭?
我发现我有一些网站连接池问题,我正在跟踪它们。 我知道有一件事要确保任何SQLDataReaders都关闭,我已经走了,并确保它们是。 我脑子里浮现的一个问题是关于返回SQLDataReaders的方法以及它们如何关闭(或不关闭)。
所以这里有我设置的东西和一些示例方法:
public static SqlDataReader ExecuteReader(SqlCommand cmd) { SqlConnection c = new SqlConnection(Properties.Settings.Default.DatabaseConn); cmd.Connection = c; c.Open(); return cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection); }
然后我有一个使用’ExecuteReader()’的方法
public static SqlDataReader GetData() { SqlCommand Query = new SqlCommand("select * from SomeTable"); return ExecuteReader(Query); }
现在说我有另一个调用’GetData’的方法。 我显然简化了一些事情
public static SqlDataReader GetMoreData() { return GetData; }
所以我的问题是,当我像这样调用’GetMoreData’时
SqlDataReader dr = GetMoreData(); //do some stuff with 'dr' dr.close();
我的所有 SqlDataReaders和连接都正确关闭了吗?
谢谢!
描述
SqlDataReader
实现IDisposable
接口。 在每个实现IDisposable
类上,您应该调用Dispose
或使用using
来释放资源,在这种情况下关闭阅读器和底层连接。
IDisposable Interface定义释放已分配资源的方法。
样品
using(SqlDataReader dr = GetMoreData()) { try { // do your stuff } catch(Exception ex) { // handle the exception } } // the reader will get closed here
要么
SqlDataReader dr; try { dr = GetMoreData(); // do your stuff } catch(Exception ex) { // handle the exception } finally { // close the reader dr.Dispose(); }
编辑
JotaBe评论不错
但是如果他实现了一个返回DataReader的方法,则应该在方法的调用者中使用using。 因此无法保证DataReader已关闭。
我不建议返回SqlDataReader
但如果你想这样做,你需要这样做
SqlDataReader reader; try { reader = methodThatReturnsAReader(); } catch(Exception ex) { // handle the exception } finally { // close the reader reader.Dispose(); }
更多信息
- MSDN – IDisposable接口
- MSDN – SqlDataReader类
只要你确定每次调用dr.Close()(即使抛出exception),那么你的连接也会关闭。 但是,将这种类型的代码包装到try / finally块中通常是一种好习惯,其中finally块包含dr.Close()语句。
另一种选择是using语句,它利用了SqlDataReader实现的IDisposable接口。
我建议你永远不要从方法返回DataReader。 您负责将DataReader关闭到方法调用者。 如果方法调用者不确定DataReader是否已关闭,即使发生exception,您也会遇到严重问题。
当然,你不应该这样做。
最糟糕的是,在某些情况下,开放的DataReader可以在数据库中创建锁。
唯一的例外是如果该方法是私有的,并且您确保所有方法调用者都在关闭DataReader。 但它仍然非常容易出错。
包含SqlDataReader dr = GetMoreData()
的using
语句将保护您,只要它在每个调用GetMoreData()
地方使用。 这很难管理,所以你可以通过改变设计来更好地保护自己。
来自Microsoft模式和实践 :
“满足以下条件时使用DataSet:
– 你必须在层之间缓存或传递数据。“
和….相比:
“满足以下条件时使用DataReader:
– 您有一个数据容器,例如可以将数据放入的业务组件。“
我会说你的应用程序有图层,似乎没有使用业务组件。 虽然DataSet的开销比DataReader大得多,但请考虑以下因素:
- 泄露连接的成本(高,不可预测)与使用DataSet的成本(可测量)
- 您需要多少数据 – 您可以返回
DataTable
或DataRow
而不是DataSet吗?
DataReader非常适合低级代码,例如数据访问组件,但不应在应用程序的不同部分之间传递。