Нужно ли вручную закрывать и утилизировать SqlDataReader? - PullRequest
80 голосов
/ 13 апреля 2009

Я работаю с устаревшим кодом здесь, и есть много случаев SqlDataReader, которые никогда не закрываются и не удаляются. Соединение закрыто, но я не уверен, нужно ли управлять считывателем вручную.

Может ли это привести к снижению производительности?

Ответы [ 4 ]

115 голосов
/ 13 апреля 2009

Старайтесь не использовать читателей, как это:

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

Вместо этого заключите их в операторы:

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

Оператор использования обеспечит правильную утилизацию объекта и освобождение ресурсов.

Если вы забудете, то оставляете уборку на сборщике мусора, что может занять некоторое время.

47 голосов
/ 13 апреля 2009

Обратите внимание, что удаление SqlDataReader, созданного с помощью SqlCommand.ExecuteReader (), не закроет / удалит базовое соединение.

Есть два общих шаблона. В первом читатель открывается и закрывается в пределах объема подключения:

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

Иногда удобно иметь метод доступа к данным, открыть соединение и вернуть читателя. В этом случае важно, чтобы возвращаемый считыватель был открыт с помощью 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;
    }
}

и вызывающему коду просто нужно расположить читателя таким образом:

using(SqlDataReader reader = ExecuteReader(...))
{
    ... do your stuff ...
} // reader and connection are closed here.
10 голосов
/ 13 апреля 2009

Чтобы быть в безопасности, оберните каждый объект SqlDataReader в , используя оператор .

5 голосов
/ 13 апреля 2009

Просто оберните ваш SQLDataReader оператором using. Это должно решить большинство ваших проблем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...