【发布时间】:2010-10-19 03:31:08
【问题描述】:
我在这里使用遗留代码,有很多 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 语句将确保正确处理对象并释放资源。
如果您忘记了,那么您将把清理工作留给垃圾收集器,这可能需要一段时间。
【讨论】:
请注意,释放使用 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
有时让数据访问方法打开连接并返回读取器很方便。在这种情况下,使用 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,那么在catch 之后在finally {} 块中调用dispose。按照这种编写方式,成功的命令永远不会被关闭或释放。
为了安全起见,请将每个 SqlDataReader 对象包装在 using statement 中。
【讨论】:
只需用“using”语句包装您的 SQLDataReader。这应该可以解决您的大部分问题。
【讨论】: