首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SqlDataReader挂起Dispose()

SqlDataReader挂起Dispose()
EN

Stack Overflow用户
提问于 2013-10-30 15:07:25
回答 3查看 3.3K关注 0票数 7

我使用以下方法对数据库执行查询并读取数据:

代码语言:javascript
复制
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(),问题就解决了。

工作版本:

代码语言:javascript
复制
    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();
            }
        } 
    }
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-10-30 17:10:16

发生异常时,在收到所有数据之前停止处理数据。即使在几行之后中止处理,也可以毫无例外地再现此问题。

当释放命令或读取器时,查询仍在服务器上运行。ADO.NET只是像mad一样读取所有剩余的行和结果集,然后丢弃它们。它这样做是因为服务器正在发送它们,并且协议要求接收它们。

调用SqlCommand.Cancel会向Server发送“注意”,从而导致查询真正中止。这与在SSMS中按下cancel按钮是一样的。

总之,当您停止处理行时,尽管有更多的行是入站的,也会发生此问题。您的解决方案(调用SqlCommand.Cancel)是正确的解决方案。

票数 9
EN

Stack Overflow用户

发布于 2013-10-30 17:17:06

关于DisposeSqlDataReader方法,MSDN (链接)可以这样说:

释放DbDataReader和调用Close所使用的资源。

我补充的重点。然后,如果您查看Close方法(链接),它将声明如下:

Close方法填充输出参数、返回值和RecordsAffected的值,从而增加关闭用于处理大型或复杂查询的SqlDataReader所需的时间。当返回值和受查询影响的记录数不显著时,在调用close方法之前,可以通过调用关联的SqlDataReader对象的Cancel方法来减少关闭SqlCommand所需的时间。

因此,如果您需要停止遍历读取器,最好像您的工作版本一样首先取消命令。

票数 2
EN

Stack Overflow用户

发布于 2013-10-30 15:58:44

我不会用这种方式来写的。

Open();不在try块中,它可以引发异常

ExecuteReader();不在try块中,它可以引发异常

我喜欢reader.Close,因为这就是我在MSDN示例中看到的。

我捕获SQLexception,因为它们有数字(比如超时)

代码语言:javascript
复制
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();
}
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19686488

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档