Нужно ли вручную закрывать и утилизировать SqlDataReader?
Я работаю с устаревшим кодом здесь, и есть много экземпляров SqlDataReader
, которые никогда не закрываются или не удаляются. Соединение закрыто, но я не уверен, нужно ли вручную управлять считывателем.
Может ли это привести к замедлению производительности?
Ответы
Ответ 1
Старайтесь избегать использования таких читателей:
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
Оператор using обеспечит правильное удаление объекта и освобождение ресурсов.
Если вы забудете, что вы уходите от уборки к сборщику мусора, это может занять некоторое время.
Ответ 2
Обратите внимание, что удаление экземпляра 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.
Ответ 3
Чтобы быть в безопасности, оберните каждый объект SqlDataReader в с помощью инструкции.
Ответ 4
Просто оберните SQLDataReader оператором "using". Это должно позаботиться о большинстве ваших проблем.