使用mysql_fetch_object时出现奇怪的MySQL错误"空行数据包正文"(PHP 5.3.3)

Dan*_*ano 10 php mysql php-5.3

当我使用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的已用内存),但这应该不是问题.

小智 19

我遇到了同样的错误.我正在使用PDO,但基本上应该是同样的事情.

你在MyISAM桌上操作吗?如果是这样,问题可能与引擎使用的锁定模型有关:它锁定整个表,用于使用共享锁读取,用于使用独占锁写入.

这就是我想要做的:读取一个没有缓冲的大结果集,并更新同一个表中的一些行.由于您在同一连接上保存无缓冲的结果集时无法发出语句,因此我尝试使用另一个连接进行更新.阅读进行得很顺利,直到第一次更新,此时脚本停滞了大约一分钟,然后我得到了"空行数据包正文"错误.

您会看到,在读取无缓冲时,将保留共享锁,直到读取整个结果集或关闭光标.在此期间,表使用共享锁锁定,因此其他连接可以获取表上的共享锁(换句话说,从中读取),但是必须等待独占锁(用于写入).如果这发生在同一个脚本中,它将会死锁.

现在,为了防止无休止的死锁,MySQL会在一段时间后强行释放你的共享锁(IIRC受table_lock_wait_timeout的值影响),转储结果集并允许带有等待的独占锁的写语句轮到它.

所以,虽然在我的情况下,它是相同的脚本,并且因此在超时到期之前停止,也可能是某些其他脚本正在尝试对表执行写操作具有相同的效果,这可能是您在案件.

解决这个问题的原因是将表类型更改为InnoDB,因为该引擎使用行级而不是表级锁.但是,既然您说数据库不是您的,那么您可能无法做到这一点.


Xen*_*nos 9

实际问题是PHP 和 MySQL 之间的连接中断(=在PHP接收到所有数据之前停止)。

当 PHP (PDO) 执行 MySQL 查询时,它会在打开的连接上发送查询,然后等待响应。响应由一组标头和一个正文组成,有点像 HTTP 请求。

如果在 PDO 未收到所有标头时连接中断,那么您将收到警告“读取结果集标头时出错”,这意味着 PDO 无法解释响应,因为它只是部分(标头)。

如果在解析正文时连接中断,则 PDO 将产生“空行数据包正文”,对应于您的错误。有关其他信息,请参阅此 Github PR

所以解决方法是找出连接被终止的原因:

  • 是因为连接超时吗?然后尝试按照建议修复配置
  • 是因为连接被`KILLè 命令手动杀死了吗?然后要求凶手停止这样做
  • 是因为 Mysql 内存已满而您的实例被您的虚拟主机杀死了吗?然后减少结果集大小/获得更大的 MySQL 服务器/要求更多 RAM
  • 是不是因为发生了“死锁”,所以Mysql任意杀了一个连接(MyISAM表更可能发生,包括内部临时表)?然后尝试使用 InnoDB
  • 是不是因为硬连接中断了,比如 PHP 和 MySQL 之间的电线/wifi 接收不良?然后修复硬件。
  • 是因为转储程序要求终止所有连接以处理转储吗?然后在运行转储之前等待现有连接完成

  • @DanieleSalvatoreAlbano这实际上仍然是今天的问题,因为它与MyISAM无关(它也会发生在InnoDB上)所以是的,它可能对OP没有帮助,但知道原因是发送正文时连接被终止/关闭数据将帮助其他人从 Duckduckgo(或邪恶的搜索引擎:))登陆这里 (3认同)
  • 这对我很有用。我正在对一些查询进行故障排除并终止了一个进程,以免等待它结束长查询。后来我在错误日志中看到了这个通知,当时无法放置。当读到这个解释时,一分钱都掉了。 (2认同)

Jes*_*Hun 6

不久前出现此错误,我通过增加的值来解决它

net_read_timeout = 360
net_write_timeout = 360
Run Code Online (Sandbox Code Playgroud)

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

  • 在你的 mysql 配置中,通常称为 my.conf,位于 mysqld 块中 (2认同)