簡體   English   中英

MySQL 連接器/NET 連接每個連接有多個 DataReaders?

[英]MySQL Connector/NET connection multiple DataReaders per Connection?

我現在從 Java 遷移到 C#,因為我意識到我更喜歡 C# 語言功能而不是 Java 中的功能,但我有這個小問題。 在 MySQL Connector/J 和 JDBC 中,我相信我的一個應用程序允許在另一個應用程序打開時執行多個PreparedStatement ,就像我可以執行一個返回ResultSet的查詢,而當ResultSet仍然打開時,我可以打開另一個PreparedStatement並獲得另一個ResultSet或者我可以根據我從我的第一個ResultSet獲得的數據執行更新(即,當我意識到該行在密碼欄)。

但是,使用連接器/NET,我開始意識到每當我嘗試這樣做時,我都會收到此錯誤: MySql.Data.MySqlClient.MySqlException: There is already an open DataReader associated with this Connection which must be closed first.

有沒有一種簡單的方法可以解決這個錯誤,也許是 MySQL 到 .NET 橋的任何其他實現? 我真的不想在一個應用程序中創建很多數據庫連接,盡管我可能想為我的應用程序中的每個線程創建一個(如在 ThreadLocal 中)。 當我以兩種不同的方法同時執行兩個查詢時,ThreadLocal DB 連接會有所幫助,但顯然我不能將這兩個命令分成不同的線程,而且我不想創建多余的線程。

順便說一下,這是代碼本身。 是的,我可以在關閉閱讀器后將更新代碼向下移動,但是我有更多類似的方法,其中一些比這個更難修復:

MySqlConnection con = DatabaseConnection.GetConnection();
MySqlCommand cmd = con.CreateCommand();
cmd.CommandText = "SELECT `id`,`password`,`salt`,`pin`,`gender`,`birthday` FROM `accounts` WHERE `name` = '" + AccountName + "'";
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
    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;
    if (!HashFunctions.HashEquals(pwd, HashAlgorithms.SHA512, passhash + salt))
    {
        if (passhash == pwd || salt == null && HashFunctions.HashEquals(pwd, HashAlgorithms.SHA1, passhash))
        {
            salt = HashFunctions.GenerateSalt();
            passhash = HashFunctions.GenerateSaltedSha512Hash(pwd, salt);
            MySqlCommand update = con.CreateCommand();
            update.CommandText = "UPDATE `accounts` SET `password` = '" + passhash + "', `salt` = '" + salt + "' WHERE `id` = " + AccountId;
            update.ExecuteNonQuery();
            update.Dispose();
        }
    }
}
reader.Close();
cmd.Dispose();

如果移動更新代碼是唯一的可能性,或者如果它是最好的,我想我將不得不使用它,但我想首先獲得有關其他可能性的更多想法,然后選擇一個選項。

不,我敢打賭,在 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();
        }
    }
}

好吧,通過更多的研究,我意識到我錯了。 Java 的 ResultSet 實際上確實保持與數據庫的活動連接,如本頁所示:www.geekinterview.com/question_details/591

必須連接 ResultSets,以便 ResultSet.next() 方法正常工作以從數據庫中獲取下一行。 請注意,這並不意味着連接正忙於為 ResultSet 提供服務,而是 ResultSet 僅保留連接,以便在收到命令時可以繼續前進。

顯然 SQL Server 有類似的東西,它允許您打開多個只讀、只進查詢,而另一個在同一連接上打開,稱為 MARS(多個活動結果集)。 http://www.codeguru.com/csharp/csharp/cs_network/database/article.php/c8715

通過更多的研究,我意識到 MySQL Connector/NET 不支持此功能。 這太糟糕了,因為我相信它比當前的實現更有意義,至少對於遷移 Java 開發人員而言。

來自MSDN

在使用SqlDataReader 的同時,關聯的SqlConnection 正忙於為SqlDataReader 服務,除了關閉SqlConnection 之外,無法對SqlConnection 執行其他操作。 在調用 SqlDataReader 的 Close 方法之前都是這種情況。 例如,只有在調用 Close 之后才能檢索輸出參數

我通常用來解決這個問題是嵌套我需要的連接,以便當我第一次使用關閉所有其他連接時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM