大约4分钟后,MySqlDataReader停止读取并返回

时间:2010-07-28 05:28:46

标签: c# sql mysql

我有一个简单的查询,返回25,026行:

MySqlCommand cmd = new MySqlCommand("SELECT ID FROM People", DB);
MySqlDataReader reader = cmd.ExecuteReader();

IDint。)如果我这样做:

int i = 0;
while (reader.Read()) i++;

i将等于25026.但是,我需要对循环中的每个ID进行一些处理;每次迭代都会在数百毫秒内完成。

int i = 0;
MySqlCommand updater = new MySqlCommand("INSERT INTO OtherTable (...)", anotherConnection);
updater.Prepare();
while (reader.Read()) {
     int id = reader.getInt32(0);
     // do stuff, then
     updater.ExecuteNonQuery();
     i++;
}

然而,在处理大约4:15之后,reader.Read()只返回false。在我的大多数测试运行中,i等于14896,但它有时也会停在11920. DataReader在相同数量的记录之后退出是可疑的,并且它在不同行数后停止的次数似乎更奇怪。

当肯定有更多行时,为什么reader.Read()会返回false?没有例外被抛出 - 甚至没有第一次机会异常。


更新:我在回复Shaun's answer时提到,我确信MySqlDataReader.Read()正在吞下异常,因此我下载了Connector/Net's source code({{ 1}})并将项目添加到我的解决方案中。果然,在处理6:15之后,例外!

bzr branch lp:connectornet/6.2 C:/local/path的调用会抛出resultSet.NextRow(),并显示“从流中读取失败”的消息。 MySqlExceptionInnerException

SocketException

10054表示TCP套接字已中止{ Message: "An existing connection was forcibly closed by the remote host", ErrorCode: 10054, SocketErrorCode: ConnectionReset } 而不是正常断开连接握手(RSTFINFIN ACK),这告诉我一些棘手的事情正在发生到网络连接。

在my.ini中,我将ACKinteractive_timeout转换为1814400(秒)无效。

那么......为什么我的连接在阅读6:15(375秒)后被拆除了?

(另外,为什么在我使用官方二进制文件时会吞下这个异常?它看起来就像它应该冒泡到我的应用程序代码一样。)

9 个答案:

答案 0 :(得分:2)

也许你有一个损坏的表 - 这个人的问题听起来与你的非常相似: http://forums.asp.net/t/1507319.aspx?PageIndex=2 - 修复表格,看看会发生什么。

如果不起作用,请继续阅读:

我的猜测是你正在遇到某种类型的死锁,特别是考虑到你正在阅读和写作。这将解释为什么它适用于简单的循环,但在您进行更新时不起作用。它也可以解释为什么它每次都在同一行/时间内发生。

SqlDataReader中有一个奇怪的错误,它阻止异常(http://support.microsoft.com/kb/316667)。在MySqlDatareader中可能有类似的东西 - 在最后的.Read()调用之后,尝试调用.NextResult()。即使它不是死锁,它也可以帮助您诊断问题。在这些类型的情况下,您希望更倾向于“信任但验证” - 是的,文档说并且异常将在时间上抛出,但有时(很少)文档存在:)对于第三方尤其如此供应商 - 例如看http://bugs.mysql.com/bug.php?id=53439 - mysql .net库有一些问题,比如你过去的问题。

另一个想法是观察数据库中正在发生的事情 - 确保在代码退出的行之前提取数据。

如果失败了,我会读取所有数据,缓存它,然后进行修改。通过批量修改,代码将更少繁琐并且执行得更快。

或者,每1000行左右重置一次阅读器(并跟踪你最近的行ID)

希望有些东西可以帮助你解决挫败感! :)

答案 1 :(得分:2)

由于我刚刚阅读int,我最终只是将整个结果集读入List<int>,关闭了读者,然后进行了处理。这对于int来说是好的,因为甚至一百万的占用率高于{1}。 100 MB的RAM,但我仍然对根本问题没有得到解决感到失望 - 如果我每行读取多个int,内存将成为大型数据集的一个非常大的问题。

答案 2 :(得分:1)

尝试设置更长的连接超时。

答案 3 :(得分:1)

有两个问题让事情变得更加混乱:

第一个,正如另一篇文章中提到的那样,旧版本的MySQL .NET连接器吞噬了超时异常。我使用的是mysql.data.dll版本6.1.x,升级到6.3.6后,异常被正确抛出。

第二个是默认的MySQL服务器超时,特别是 net_read_timeout net_write_timeout (分别默认为30秒和60秒)。

对于旧版本的mysql.data.dll,当您使用datareader循环中的数据执行操作并且超过60秒的默认超时时,它将只是坐在那里而不做任何事情。对于较新的版本,它会正确地抛出超时异常,这有助于诊断问题。

希望这可以帮助某人,因为我偶然发现了这一点,但解决方案是使用不同的方法,而不是实际原因/修复。

TLDR :my.ini中的mysql服务器上的修复增加了 net_read_timeout net_write_timeout ,尽管升级mysql.data.dll是一个好主意。

答案 4 :(得分:0)

可能这是服务器端的超时?

答案 5 :(得分:0)

尝试在MySqlCommand上设置超时,而不是在“cmd”和“updater”上设置MySqlConnection。 如果您执行以下操作会发生什么:SELECT TOP 100 ID FROM PEOPLE

答案 6 :(得分:0)

试试这个 1.添加参考System.Transactions;

using(TransactionScope scope = new TransactionScope())
{
       //Initialize connection
       // execute command
     :
     :
     scope.Complete();
}

使用Scope编写整个插入/更新逻辑。这肯定会帮助你。

答案 7 :(得分:0)

创建命令后添加以下内容。

cmd.CommandTimeout = 0;

这会将CommandTimeout设置为无限期。您获得超时的原因可能是因为执行的连接仍处于“命令”阶段,因为Reader。

尝试设置CommandTimeout = 0或首先读取所有内容,然后对结果执行后续功能。否则,我唯一可能看到的另一个问题是,由于服务器本身超时,Sql Server正在针对指定的进程ID丢弃结果集。

答案 8 :(得分:0)

我在这里找到了一篇文章 http://corengen.wordpress.com/2010/06/09/mysql-connectornet-hangs-on-mysqldatareader-read/

这个家伙所经历的是类似的东西:在读取同一记录的过程中,在完全相同的时刻挂上了Read方法(这与我猜的相同)。 在他的情况下,他在Read()循环期间调用另一个web服务,并且一个超时导致Read()挂起而没有异常。

在你的机器上是否可以相同,Read()循环中的更新超时(我认为更新使用默认的30秒超时)并产生相同的效果?

也许是一个长镜头,但读这两个故事听起来很多人。