使用mysql_fetch_object时出现奇怪的MySQL错误“Empty row packet body”(PHP 5.3.3)

oyxsuwqo  于 2023-03-22  发布在  Mysql
关注(0)|答案(8)|浏览(253)

当我使用PHP从资源(查询)中获取行时,我得到了一个非常奇怪,毫无意义和完全随机的错误。
我的开发机器是Windows XP SP3与Apache 2.2,而MySQL运行在虚拟机上,使用Ubuntu 10.04,768 MB的RAM,100 GB的HDD和4个逻辑核心(Intel q6600)。然而,这个问题与Windows上的PHP无关,因为当我在数据库机器上运行代码时,我得到了相同的错误。
我正在使用mysql扩展(不是mysqlimysqlnd),但环顾四周,我发现了一个关于mysqlnd扩展相关错误的补丁,所以,也许,我应该试试。
主要问题是当我执行这个查询时(一个非常大的查询,有几个派生表和20多个连接),处理结果很快,一切都很顺利,但是当我的代码花了大约15/20秒来处理一个行块时(我需要从一个以非常特定的方式链接的行块中构建一个对象,我不能改变这一点,数据库不是我的,并从这个对象制作一些PDF)一段时间后(随机时间)我得到这个错误“空行包体”。
我使用无缓冲查询来减少内存消耗(如果启用缓冲,我会使用大约260 MB的内存),但这不应该是问题所在。

r6vfmomb

r6vfmomb1#

我遇到了同样的错误。我正在使用PDO,但基本上应该是一样的。
您是否在MyISAM表上操作?如果是,问题可能与此Engine使用的锁定模型有关:它锁定整个表,对于阅读使用共享锁,对于写入使用排他锁。
这就是我想做的读取一个无缓冲的大结果集,并更新同一个表中的一些行。由于在同一个连接上不能发出一条语句,而它持有一个无缓冲的结果集,我尝试使用另一个连接进行更新。阅读一直很顺利,直到第一次更新,在这一点上脚本停顿了大约一分钟,然后我得到了“空行包体”错误。
你看,当阅读无缓冲时,共享锁会一直保持,直到整个结果集被读取或游标被关闭。在此期间,表被共享锁锁定,因此其他连接可以获得表上的共享锁(换句话说,从表中读取),但独占锁(用于写入)必须等待。如果在同一脚本中发生这种情况,它将死锁。
现在,为了防止无休止的死锁,MySQL将在一段时间后强制释放您的共享锁(IIRC这受table_lock_wait_timeout值的影响),转储您的结果集并允许具有等待排他锁的写入语句轮到它。
因此,虽然在我的例子中,是同一个脚本执行了此操作,因此在超时到期之前一直处于停滞状态,但也可能是其他脚本正在尝试对表执行具有相同效果的写操作,这可能就是您的例子中发生的情况。
对我来说,解决问题的方法是将表类型更改为InnoDB,因为该引擎使用行级锁而不是表级锁。然而,由于您说数据库不是您的,这对您来说可能不可能。

sbtkgmzw

sbtkgmzw2#

实际的问题是PHP和MySQL之间的连接中断(=在PHP * 接收 * 所有数据之前停止)。
当PHP(PDO)执行MySQL查询时,它在打开的连接上发送查询,然后等待响应。响应由一组头和一个主体组成,有点像HTTP请求。
如果连接中断,而PDO没有收到所有的头,那么你会得到一个警告“错误阅读结果集的头”,这意味着PDO不能解释响应,因为它只是部分(头)。
如果在解析包体时连接断开,那么PDO将产生一个“空行包体”,对应于您的错误。有关其他信息,请参阅this Github PR
因此,解决方法是找出连接被终止的原因:

  • 是因为连接超时了吗?那就按照建议修复配置吧
  • 是因为连接被`KILLè命令手动杀死了吗?然后要求杀手停止这样做
  • 是因为Mysql内存满了,你的示例被你的虚拟主机杀死了吗?那就减少结果集的大小/找一个更大的MySQL服务器/要求更多的内存
  • 是不是因为发生了“死锁”,所以Mysql任意终止了一个连接(MyISAM表更有可能发生这种情况,包括内部临时表)?
  • 是因为硬件连接中断了吗,比如PHP和MySQL之间的有线/WiFi接收不好?然后修复硬件。
  • 是因为转储程序要求终止所有连接以处理转储吗?然后等待现有连接完成,再运行转储
qc6wkl3g

qc6wkl3g3#

不久前出现了这个错误,我通过增加

net_read_timeout = 360
net_write_timeout = 360

当一个连接在写入时打开,等待另一个查询结束以继续插入,这会超时,给出一个空行包。我正在处理非常大的数据集,使用的值超过360。您的值将取决于您的用例。

pod7payv

pod7payv4#

user589182的答案是正确的。我正在做本质上相同的事情:从同一个PHP脚本中读取一个无缓冲的大型结果集,并更新同一个表中的一些行。在大约2500次更新后,我得到了完全相同的错误消息。从MyISAM切换到InnoDB后,问题解决了。

ep6jt1vc

ep6jt1vc5#

我得到了同样的错误,而且在更新同一个表的行时,我也在阅读一个未缓冲的大型结果集。
与其切换到InnoDB,一个更好的解决方案可能是创建一个临时表,只包含原始表的主键。然后,在该临时表中循环,同时从原始表中每次选择和更新一行。您必须使用两个单独的MySQL连接才能完成此操作,否则您将获得“Commands out of sync”错误。
您可能需要锁定原始表,以防止其他任何人在此过程中对其进行阅读/写。

5rgfhyps

5rgfhyps6#

我在InnoDB上从来没有遇到过这种类型的问题,直到我切换了编码环境(字面上的意思,就像位置)。所以,如果你改变了你的无线连接,这可能是问题,特别是如果它是一个公共场所。

wj8zmpe1

wj8zmpe17#

我现在遇到了同样的问题,阅读巨大的无缓冲查询。所有的表都是InnoDB的。
当另一个进程启动mysqldump时,它就停止了。所以这可能也是原因。

sczxawaw

sczxawaw8#

我的“身体中的空行包”和其他一些相关的随机错误是由网络路由器引起的。
通过绕过路由器,直接连接到互联网,我没有更多像这样的奇怪错误。

  • 直接在PHPMYADMIN中运行查询,查看是否遇到错误,如果没有,则检查本地环境(如网络)是否存在问题。

相关问题