当我使用PHP从资源(查询)获取行时,我得到一个非常奇怪,毫无意义且完全随机的错误。
我的开发机器是带有Apache 2.2的Windows XP SP3,而MySQL运行在虚拟机上,使用ubuntu 10.04,带有768mb的RAM,100GB的HDD和4个逻辑核心(Intel q6600)。但是这个问题与Windows上的PHP无关,因为当我在数据库机器上运行代码时遇到同样的错误。
我正在使用mysql
扩展名(不是mysqli
或mysqlnd
),但环顾四周我创建了一个关于与mysqlnd扩展相关的错误的补丁,所以,我可能会尝试
主要的问题是,当我执行这个查询时(一个包含几个派生表和超过20个连接的真正大的查询)并且处理结果很快并且一切顺利,但是当我的代码花费大约15/20秒时处理一个行块(我需要从它们之间以非常特殊的方式链接的行块构建一个对象,我不能改变它,数据库不是我的,并且从这个对象生成一些PDF)一段时间后(随机时间)我收到此错误“空行数据包正文”。
我使用无缓冲的查询来减少内存消耗(如果我启用缓冲,我会得到大约260MB的已用内存),但这应该不是问题。
答案 0 :(得分:18)
我遇到了同样的错误。我正在使用PDO,但基本上应该是同样的事情。
您是否在MyISAM桌面上操作?如果是这样,问题可能与引擎使用的锁定模型有关:它锁定整个表,用于使用共享锁读取,用于使用独占锁写入。
这就是我想要做的:读取一个没有缓冲的大型结果集,并更新同一个表中的一些行。由于您在同一连接上保存无缓冲的结果集时无法发出语句,因此我尝试使用另一个连接进行更新。阅读进行到第一次更新,此时脚本停止了大约一分钟,然后我收到了“空行数据包正文”错误。
您会看到,在读取无缓冲时,将保留共享锁,直到读取整个结果集或关闭光标。在此期间,表使用共享锁锁定,因此其他连接可以获取表上的共享锁(换句话说,从中读取),但是必须等待独占锁(用于写入)。如果在同一个脚本中发生这种情况,它将会死锁。
现在,为了防止无休止的死锁,MySQL会在一段时间后强行释放你的共享锁(IIRC这会受到table_lock_wait_timeout的值的影响),转储你的结果集并允许带有等待的独占锁的写语句轮到它
所以,虽然在我的情况下,它是相同的脚本,并且因此停止直到超时到期,也可能是某些其他脚本正在尝试对表执行写操作具有相同的效果,这可能是什么在你的情况下发生了。
解决了我的问题是将表类型更改为InnoDB,因为该引擎使用行级而不是表级锁。但是,既然您说数据库不是您的,那么您可能无法做到这一点。
答案 1 :(得分:6)
一段时间以前出现此错误,我通过增加
的值来修复它net_read_timeout = 360
net_write_timeout = 360
当一个连接在写入时打开,等待另一个查询结束以继续插入时,这会超时,从而产生一个空行数据包。我正在处理非常大的数据集,使用的值超过360.您的价值将取决于您的使用案例。
答案 2 :(得分:0)
user589182的回答是现货。我基本上做同样的事情:读取一个没有缓冲的大结果集,并从同一个PHP脚本更新同一个表中的一些行。我得到完全相同的错误信息约。 2500更新。从MyISAM切换到InnoDB后问题解决了。
答案 3 :(得分:0)
我得到了同样的错误,我在更新同一个表的行时也读取了一个没有缓冲的大结果集。
更好的解决方案可能是创建一个仅包含原始表主键的临时表,而不是切换到InnoDB。然后,循环访问该临时表,同时从原始表中一次选择并更新一行。您必须使用两个单独的MySQL连接才能执行此操作,否则您将收到“命令不同步”错误。
您可能需要锁定原始表格以防止其他人在发生这种情况时进行读/写操作。
答案 4 :(得分:0)
我在InnoDB上,在切换编码环境(字面意思,就像位置)之前从未遇到过这种类型的问题。因此,如果您更改了无线连接,这可能是问题,特别是如果它是一个公共场所。
答案 5 :(得分:0)
我现在遇到同样的问题,读取了巨大的无缓冲查询。所有的表都是InnoDB。
并且它在另一个进程启动mysqldump
时停止。所以这也可能是原因。
答案 6 :(得分:0)
实际问题是 PHP和MySQL之间的连接中断(=在PHP 接收所有数据之前已将其终止)。
当PHP(PDO)执行MySQL查询时,它将在打开的连接上发送查询,然后等待响应。响应由一组标头和主体组成,某种程度上类似于HTTP请求。
如果在PDO尚未收到所有标头的情况下断开了连接,则您将收到警告“错误读取结果集的标头”,这意味着PDO无法解释响应,因为它只是部分(标头)。
如果在解析正文时连接断开,则PDO将生成一个“空行数据包正文”,与您的错误相对应。有关其他信息,请参见this Github PR
因此,解决方法是查找连接被终止的原因: