是否有必要手动关闭和处置SqlDataReader?

Jon*_*bey 84 .net c# sql ado.net

我在这里使用遗留代码,并且有许多实例SqlDataReader从未关闭或处置.连接已关闭,但我不确定是否有必要手动管理阅读器.

这会导致性能下降吗?

Cod*_*ain 116

尽量避免使用这样的读者:

SqlConnection connection = new SqlConnection("connection string");
SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection);
SqlDataReader reader = cmd.ExecuteReader();
connection.Open();
if (reader != null)
{
      while (reader.Read())
      {
              //do something
      }
}
reader.Close(); // <- too easy to forget
reader.Dispose(); // <- too easy to forget
connection.Close(); // <- too easy to forget
Run Code Online (Sandbox Code Playgroud)

而是将它们包装在using语句中:

using(SqlConnection connection = new SqlConnection("connection string"))
{

    connection.Open();

    using(SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection))
    {
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            if (reader != null)
            {
                while (reader.Read())
                {
                    //do something
                }
            }
        } // reader closed and disposed up here

    } // command disposed here

} //connection closed and disposed here
Run Code Online (Sandbox Code Playgroud)

using语句将确保正确处理对象和释放资源.

如果你忘了那么你就要把清洁工作留给垃圾收集器,这可能需要一段时间.

  • 在任一示例中都不需要.Close()语句:它由.Dispose()调用处理. (24认同)
  • 可能想要检查它.HasRows而不是null. (7认同)
  • @JohH:示例中的while(reader.Read())与.HasRows完成相同的操作,并且无论如何都需要.Read将读者前进到第一行. (7认同)
  • @Andrew如果ExecuteReader抛出异常,它怎么能返回null? (3认同)

Joe*_*Joe 50

请注意,使用SqlCommand.ExecuteReader()实例化处置SqlDataReader 不会关闭/处置基础连接.

有两种常见的模式.在第一个中,读者在连接范围内打开和关闭:

using(SqlConnection connection = ...)
{
    connection.Open();
    ...
    using(SqlCommand command = ...)
    {
        using(SqlDataReader reader = command.ExecuteReader())
        {
            ... do your stuff ...
        } // reader is closed/disposed here
    } // command is closed/disposed here
} // connection is closed/disposed here
Run Code Online (Sandbox Code Playgroud)

有时,使用数据访问方法打开连接并返回阅读器很方便.在这种情况下,使用CommandBehavior.CloseConnection打开返回的阅读器非常重要,这样关闭/部署阅读器将关闭底层连接.模式看起来像这样:

public SqlDataReader ExecuteReader(string commandText)
{
    SqlConnection connection = new SqlConnection(...);
    try
    {
        connection.Open();
        using(SqlCommand command = new SqlCommand(commandText, connection))
        {
            return command.ExecuteReader(CommandBehavior.CloseConnection);
        }
    }
    catch
    {
        // Close connection before rethrowing
        connection.Close();
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且调用代码只需要处理读者:

using(SqlDataReader reader = ExecuteReader(...))
{
    ... do your stuff ...
} // reader and connection are closed here.
Run Code Online (Sandbox Code Playgroud)

  • SqlCommand对象上没有Close()方法. (2认同)
  • 这不好。如果你*真的*不能忍受使用`using`,那么在catch之后的`finally {}`块中调用dispose。按照这种编写方式,成功的命令永远不会被关闭或处置。 (2认同)
  • @smdrager,如果你仔细阅读答案,他正在谈论一种让读者回归的方法.如果使用.ExecuteReader(CommandBehavior.CloseConnection); 然后通过处理READER,连接将被关闭.因此调用方法只需要将结果读取器包装在using语句中.使用(var rdr = SqlHelper.GetReader()){// ...}如果你在finally块中关闭它,那么你的读者将无法读取,因为连接已关闭. (2认同)

Kon*_*Kon 10

为安全起见,请将每个SqlDataReader对象包装在using语句中.

  • 续......"你可以通过将对象放在try块中然后在finally块中调用Dispose来实现相同的结果;实际上,这就是编译器如何翻译using语句." (5认同)
  • using 语句与将 DataReader 代码包装在 try..finally... 块中相同,并在 finally 部分中使用 close/dispose 方法。基本上,它只是“保证”该对象将被正确处理。 (2认同)
  • 这直接来自我提供的链接:“ using 语句确保即使在调用对象方法时发生异常,也会调用 Dispose。” (2认同)

J.W*_*.W. 5

只需使用"using"语句包装SQLDataReader即可.这应该照顾你的大部分问题.