关闭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的成本(可测量)
  • 您需要多少数据 – 您可以返回DataTableDataRow而不是DataSet吗?

DataReader非常适合低级代码,例如数据访问组件,但不应在应用程序的不同部分之间传递。