[英]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.