Здесь я работаю с устаревшим кодом, и многие его экземпляры SqlDataReaderникогда не закрываются и не удаляются. Соединение закрыто, но я не уверен, нужно ли управлять считывателем вручную.
Может ли это вызвать снижение производительности?
Здесь я работаю с устаревшим кодом, и многие его экземпляры SqlDataReaderникогда не закрываются и не удаляются. Соединение закрыто, но я не уверен, нужно ли управлять считывателем вручную.
Может ли это вызвать снижение производительности?
Ответы:
Старайтесь избегать использования таких читателей:
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:
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 обеспечит правильное удаление объекта и освобождение ресурсов.
Если вы забудете, вы оставите уборку сборщику мусора, что может занять некоторое время.
Обратите внимание, что удаление экземпляра 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.
usings, тогда вызовите dispose в finally {}блоке после catch. Как это написано, успешные команды никогда не будут закрыты или удалены.
На всякий случай оберните каждый объект SqlDataReader в оператор using .