我使用以下方法对数据库执行查询并读取数据:
using(SqlConnection connection = new SqlConnection("Connection string"))
{
connection.Open();
using(SqlCommand command = new SqlCommand("SELECT * FROM TableName", connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
// read and process data somehow (possible source of exceptions)
} // <- reader hangs here if exception occurs
}
}在读取和处理数据时,可能会出现一些异常。问题是当抛出异常时,DataReader挂起Close()调用。你知道为什么吗?如何妥善解决这一问题?当我编写try..catch..finally块而不是using,在用finally处理读取器之前调用command.Cancel(),问题就解决了。
工作版本:
using(SqlConnection connection = new SqlConnection("Connection string"))
{
connection.Open();
using(SqlCommand command = new SqlCommand("SELECT * FROM TableName", connection))
{
SqlDataReader reader = command.ExecuteReader();
try
{
// read and process data somehow (possible source of exceptions)
}
catch(Exception ex)
{
// handle exception somehow
}
finally
{
command.Cancel(); // !!!
reader.Dispose();
}
}
}发布于 2013-10-30 17:10:16
发生异常时,在收到所有数据之前停止处理数据。即使在几行之后中止处理,也可以毫无例外地再现此问题。
当释放命令或读取器时,查询仍在服务器上运行。ADO.NET只是像mad一样读取所有剩余的行和结果集,然后丢弃它们。它这样做是因为服务器正在发送它们,并且协议要求接收它们。
调用SqlCommand.Cancel会向Server发送“注意”,从而导致查询真正中止。这与在SSMS中按下cancel按钮是一样的。
总之,当您停止处理行时,尽管有更多的行是入站的,也会发生此问题。您的解决方案(调用SqlCommand.Cancel)是正确的解决方案。
发布于 2013-10-30 17:17:06
发布于 2013-10-30 15:58:44
我不会用这种方式来写的。
Open();不在try块中,它可以引发异常
ExecuteReader();不在try块中,它可以引发异常
我喜欢reader.Close,因为这就是我在MSDN示例中看到的。
我捕获SQLexception,因为它们有数字(比如超时)
SqlConnection connection = new SqlConnection();
SqlDataReader reader = null;
try
{
connection.Open(); // you are missing this as a possible source of exceptions
SqlCommand command = new SqlCommand("SELECT * FROM TableName", connection);
reader = command.ExecuteReader(); // you are missing this as a possible source of exceptions
// read and process data somehow (possible source of exceptions)
}
catch (SqlException ex)
{
}
catch (Exception ex)
{
// handle exception somehow
}
finally
{
if (reader != null) reader.Close();
connection.Close();
}https://stackoverflow.com/questions/19686488
复制相似问题