【问题标题】:closing SQLDataReaders - how to tell if they are closed?关闭 SQLDataReader - 如何判断它们是否已关闭?
【发布时间】:2012-05-08 21:38:44
【问题描述】:

我发现我遇到了一些网站连接池问题,我正在跟踪这些问题。我知道要寻找的一件事是确保所有 SQLDataReader 都已关闭,但我已经完成并确保它们已关闭。我脑海中突然出现的一个问题是关于返回 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();

all 我的 SqlDataReaders 和连接是否正确关闭?

谢谢!

【问题讨论】:

  • 您说“all”,但您只有一个阅读器和一个连接。从查看您的代码来看,如果没有引发异常,则在关闭阅读器时都应该关闭。
  • 如果您的//do some stuff with 'dr' 部分抛出异常,那么,不,您的阅读器没有正确关闭。 dknaack 的回答通过告诉您使用 using 语句来修复该错误。
  • 我看到您使用的是静态函数。您不会在真实代码中使用任何静态字段来放置阅读器或连接吗?

标签: c# database-connection connection-pooling sqldatareader


【解决方案1】:

说明

SqlDataReader 实现了IDisposable 接口。 在每个实现IDisposable 的类上,您应该调用Dispose 或使用using 为了释放资源,在这种情况下关闭阅读器和底层连接。

IDisposable 接口定义释放分配资源的方法。

样本

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();
}

更多信息

【讨论】:

  • 是的,这是真的,但是如果他实现了一个返回 DataReader 的方法,则应该在方法的调用者中使用 using。因此无法保证 DataReader 已关闭。这是一个设计缺陷!
【解决方案2】:

只要您确定每次都调用 dr.Close()(即使在抛出异常的情况下),那么您的连接也会关闭。但是,将这种类型的代码包装到 try/finally 块中通常是一种好习惯,其中 finally 块包含 dr.Close() 语句。

另一种选择是 using 语句,它利用 SqlDataReader 实现的 IDisposable 接口。

【讨论】:

    【解决方案3】:

    我建议您永远不要从方法中返回 DataReader。您将关闭 DataReader 的责任交给方法调用者。如果方法调用者不能确保 DataReader 已关闭,即使发生异常,您也会遇到严重的麻烦。

    当然,你不应该这样做。

    最糟糕的是,在某些情况下,打开的 DataReader 会在数据库中创建锁。

    唯一的例外是方法是私有的,并且您确保所有方法调用者都在关闭 DataReader。但它仍然很容易出错。

    【讨论】:

      【解决方案4】:

      包裹在SqlDataReader dr = GetMoreData() 周围的using 语句将保护您,只要在调用GetMoreData() 的每个地方都使用它。这很难管理,因此您可以通过更改设计更好地保护自己。

      来自Microsoft Patterns and Practices

      "当满足以下条件时使用DataSet:

      -你必须在层之间缓存或传递数据。”

      对比:

      "当满足以下条件时使用 DataReader:

      -您有一个数据容器,例如可以将数据放入其中的业务组件。”

      我会说您的应用程序有层并且似乎没有使用业务组件。虽然 DataSet 的开销确实比 DataReaders 大得多,但请考虑一下:

      • 泄露连接的成本(高、不可预测)与使用 DataSet 的成本(可衡量)
      • 您需要多少数据 - 您能否返回 DataTableDataRow 而不是 DataSet?

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-04
        • 2012-05-01
        • 1970-01-01
        • 2010-09-27
        • 2012-10-07
        • 1970-01-01
        相关资源
        最近更新 更多