MySQL Connector / NET连接每个连接多个DataReader?

时间:2010-09-10 14:18:03

标签: .net mysql database-connection sqldatareader mysql-connector

嘿伙计们,我正在从Java迁移到C#,因为我已经意识到我更喜欢C#语言功能而不是Java语言,但我有这个小问题。在MySQL Connector / J和JDBC中,我相信我的一个应用程序允许执行多个PreparedStatement而另一个是打开的,就像我可以执行返回ResultSet的查询一样{ {1}}仍处于打开状态,我可以打开另一个ResultSet并获取另一个PreparedStatement,或者我可以根据我从第一个ResultSet获得的数据执行更新(即,当我意识到该行在密码列中有明文密码时,插入一个salt值并使用SHA512哈希更新密码列。)

然而,使用Connector / NET,我已经意识到每当我尝试这样做时,我都会收到此错误: ResultSet

是否有一种简单的方法来修复此错误,可能是MySQL到.NET桥的任何其他实现?我真的不想在一个应用程序中创建大量的数据库连接,尽管我可能想为我的应用程序中的每个线程创建一个(如在ThreadLocal中)。当我在两种不同的方法中同时执行两个查询时,ThreadLocal数据库连接将有所帮助,但显然我不能将这两个命令分成不同的线程,我不想创建多余的线程。

顺便说一句,这是代码本身。是的,我可以将更新代码移到我关闭阅读器后,但我有更多类似的方法,其中一些比这个更难修复:

MySql.Data.MySqlClient.MySqlException: There is already an open DataReader associated with this Connection which must be closed first.

如果移动更新代码是唯一的可能性,或者它是最好的,我想我将不得不用它做,但我想首先获得更多关于其他可能性的想法,然后选择一个选项。 / p>

3 个答案:

答案 0 :(得分:2)

不,我打赌在java世界中也是如此。

正在积极使用/保持连接以检索该数据,如果在java世界中有效,那是因为它执行了以下操作之一:

  • 读取/缓存整个结果集
  • 在幕后单独进行连接

我在一个问题上看不多,你只需要移动阅读器。关闭代码中的适当位置。也就是说,无论如何都应该检查代码,因为如果发生异常,将无法正确调用dispose / close调用。使用using语句可以确保所有内容都被正确释放,在代码的修改版本下面进行这些更改(以及其他几个使其不太深入的更改):

using(MySqlConnection con = DatabaseConnection.GetConnection())
using(MySqlCommand cmd = con.CreateCommand())
{
    cmd.CommandText = "SELECT `id`,`password`,`salt`,`pin`,`gender`,`birthday` FROM `accounts` WHERE `name` = '" + AccountName + "'";
    using(MySqlDataReader reader = cmd.ExecuteReader())
    {
        if(!reader.Read()) return;
        AccountId = reader.GetInt32(0);
        string passhash = !reader.IsDBNull(1) ? reader.GetString(1) : null;
        string salt = !reader.IsDBNull(2) ? reader.GetString(2) : null;
        m_pin = !reader.IsDBNull(3) ? reader.GetString(3) : null;
        Gender = !reader.IsDBNull(4) ? reader.GetByte(4) : WvsCommon.Gender.UNDEFINED;
        m_birthday = !reader.IsDBNull(5) ? reader.GetInt32(5) : 0;
        reader.Close();
        if (HashFunctions.HashEquals(pwd, HashAlgorithms.SHA512, passhash + salt))
            return;
        if(passhash != pwd && !(salt == null && HashFunctions.HashEquals(pwd, HashAlgorithms.SHA1, passhash)))
            return;
        salt = HashFunctions.GenerateSalt();
        passhash = HashFunctions.GenerateSaltedSha512Hash(pwd, salt);
        using(MySqlCommand update = con.CreateCommand())
        {
           update.CommandText = "UPDATE `accounts` SET `password` = '" + passhash + "', `salt` = '" + salt + "' WHERE `id` = " + AccountId;
           update.ExecuteNonQuery();
        }
    }
}

答案 1 :(得分:2)

好吧,经过一番研究,我意识到自己错了。事实上,Java的ResultSet实际上与数据库保持着一个活动的连接,如本页所示: www.geekinterview.com/question_details/591

必须连接ResultSet,以便ResultSet.next()方法正常工作以从数据库中获取下一行。请注意,这并不意味着连接正忙于为ResultSet提供服务,而是ResultSet仅保留连接,以便在给出命令时它可以向前移动。

显然,SQL服务器具有与此类似的功能,允许您打开多个只读,仅向前查询,而另一个在同一连接上打开,称为MARS(多个活动结果集)。 http://www.codeguru.com/csharp/csharp/cs_network/database/article.php/c8715

通过更多研究,我意识到MySQL Connector / NET不支持此功能。这太糟糕了,因为我认为它比当前的实现更有意义,至少对迁移Java开发人员来说是这样。

答案 2 :(得分:0)

来自MSDN

  

在使用SqlDataReader时,   关联的SqlConnection正忙   提供SqlDataReader,没有   可以执行其他操作   除了关闭之外的SqlConnection   它。在关闭之前就是这种情况   调用SqlDataReader的方法。   例如,您无法检索   输出参数,直到你打电话   关闭

我通常要解决此问题的方法是嵌套我需要的连接,以便在第一次使用时关闭所有其他连接。