如何判断SqlConnection是否附加了SqlDataReader?

问题描述 投票:12回答:12

现在这更像是一种好奇而不是实际目的。如果你打开SqlConnection并附加一个SqlDataReader,然后尝试使用相同的SqlConnection运行另一个查询,那么它将抛出一个错误。我的问题是SqlConnection如何知道读者与之相关。 HasDataReader没有公共财产或任何东西,所以SqlConnection班怎么知道?

原始问题:(不再相关)

嗨,我正在为连接池和我们发生的更常见的错误设置一个小东西(它总是一个简单的修复,但我们不记得reader.Close()!)它是当我们有一个连接是很多类/方法都使用了一个方法,一个方法打开一个数据读取器并忘记关闭它。这并不是很糟糕,因为很多时候你需要做的就是进入调试器并升级到一个级别并在它之前看到它并检查它是否有一个未闭合的数据读取器。

现在,这是一个更大的问题。在这个连接池中,如果一个datareader是打开的,那么直到一个线程获得连接并尝试使用它并且最初打开数据读取器的东西可能不再存在时,它就不可知。

非常简单,如何检测数据读取器是否在连接上打开,是否有办法在不关闭连接的情况下关闭阅读器?

c# .net sql ado.net
12个回答
13
投票

SqlConnection如何知道读者是否附加到它上面

据我所知,SQLConnection知道它附有一个阅读器,因为它在内部维护了对它的引用。

明智地使用Reflector显示SQLConnection对象具有DBConnectionInternal类型的私有字段,该字段由此抽象类的许多具体实现之一填充。当您尝试向连接添加第二个实时读取器时,在内部连接上调用方法“ValidateConnectionForExecute”,并且这将追溯到内部“ReferenceCollection”的检查。当这显示现有的实时阅读器时,会抛出异常。

我想,如果你想,你可以在运行时通过反射来挖掘所有这些。


0
投票

根据article,你应该在完成后关闭阅读器,即使你使用了一个使用块。使用块将关闭连接,但不会关闭阅读器。为什么不一致?甘拜下风。



0
投票

使用新创建的命令对象创建具有相同连接和新数据读取器的新命令对象。这样可以正常工作。


13
投票

确保关闭数据站(和数据库连接)的方法是始终在using块中打开它们,如下所示:

using (SqlDataReader rdr = MySqlCommandObject.ExecuteReader())
{
    while (rdr.Read())
    {
        //...
    }
} // The SqlDataReader is guaranteed to be closed here, even if an exception was thrown.

4
投票

没人真的回答了伯爵的问题。 (“你为什么这样做?”不是答案。)我认为答案是你只能通过查看连接本身来判断连接是否有与之关联的开放数据阅读器。该连接不会公开任何会告诉您的属性。打开连接将其State属性设置为ConnectionState.Open。在其上打开数据读取器不会更改连接状态。 ConnectionState.Fetching等状态值仅在数据操作(如SqlDataReader.Read())正在进行时使用。当连接只是坐在Reads之间时,连接状态就是Open。因此,要确定打开的阅读器何时使用连接,您必须检查可能正在使用它的阅读器的状态。


2
投票

哇..很多人没有回答这个问题!没有人提到的是多线程应用程序。我想这里的每个人都有这样一个事实:你必须关闭阅读器,但我似乎没有看到任何人解决的事实是当下一个请求进来时读者可能无法完成。例如..我有一张桌子这是通过一个单独的线程填充,以便我保持UI交互。在连接正在使用时,让第二个第三个和第四个线程等待会很好。然后,当它释放出来做生意。如果没有一个简洁的方法来确定连接是否连接了一个阅读器,我必须花几分钟时间为每个可能想要使用该连接的类中的每个读者创建一些静态布尔标志系统。比需要复杂得多


1
投票

然后尝试使用相同的SqlConnection运行另一个查询然后它将抛出一个错误。

当然,你可以启用Multiple Active Result Sets - 然后它不会抛出。当然有一些局限性(总是不存在?),但它会起作用。当然,这仅用于嵌套操作。如果问题是你不小心打开了一些东西(你应该已经关闭),那么答案就是(如前所述)using


0
投票

为避免这种情况,请将DataReader包装在using块中,这样可以保证它像这样处理连接:

using (IDataReader reader = command.ExecuteReader())
{
      //do stuff
}

IDataReader上有一个名为IsClosed的属性,它会告诉你它的状态。


0
投票

检查它是否打开,如果是,请关闭它。单挑,如果您使用的是SqlHelper类,这是一个错误 - 在某些情况下它不会关闭连接。解决方案是在代码中使用try / catch或使用块,具体取决于您是否是2.0之前的版本。


0
投票

您也可以使用委托,如果由于任何原因您无法使用using clausule,那么下面是一个如何实现该目的的示例:

public delegate void TransactionRunner(DbConnection sender, DbTransaction trans, object state);

public void RunTransaction(TransactionRunner runner, object state)
    {
        RunTransaction(runner, IsolationLevel.ReadCommitted, state);
    }

public void RunTransaction(TransactionRunner runner, IsolationLevel il, object state)
    {

        DbConnection cn = GetConnection from pool
        DbTransaction trans = null;

        try
        {  
            trans = cn.BeginTransaction(il);
            runner(cn, trans, state);
            trans.Commit();
        }
        catch (Exception err)
        {
            if (trans != null)
                trans.Rollback();
            throw err;
        }
        finally
        {
            //Here you can close anything that was left open
        }
    }

然后当你需要使用它时,只需使用该函数并将函数传递为

public void DoStuff(){
    TransactionRunner tr = new TransactionRunner(MyFunction);
    RunTransaction(tr, <a parameter>);
}
public void DoStuffInternal(DbConnection cn, DbTransaction trans, object state){
    //Do Stuff and Im sure that the transaction will commit or rollback
}

现在在.Net 3.5中看起来有点矫枉过正了,但这就是我们当时在.Net 1.0中做到的...希望它有帮助......


0
投票

今天我也遇到了同样的情况但是......网上没有运气。

因此,我编写了以下代码来查找是否在连接中打开了阅读器,或者通常查找是否已准备好使用连接:

private bool IsConnectionReady(SqlConnection Connection)
{
    bool nRet = true;

    try
    {
        String sql = "SELECT * FROM dummy_table";

        using (SqlCommand cmd = new SqlCommand(sql, Connection))
        {
            using (SqlDataReader rdr = cmd.ExecuteReader())
            { }
        }
    }
    catch (Exception ex)
    {
        nRet = false;
    }

    return nRet;
}

“dummy_table”是我的数据库中的空虚表,用于检查可访问性。

这只是一种解决方法,但我应该让事情有效,并且能够在任何情况下检查连接可用性。

所以,我希望它对你有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.