5

我正在重用一个变量来存储两个不同的 PDO mysql 语句:

$stmt=$dbh->prepare("SELECT ....");   
$stmt->execute();

$stmt=$dbh->prepare("UPDATE ....");
//crash here: 
//*** Error in `/opt/lampp/bin/httpd': free(): invalid pointer: 0xf4a028dc ***
//*** Error in `/opt/lampp/bin/httpd': free(): invalid pointer: 0xf4a028dc ***
//[Mon Jun 03 19:53:48.691674 2013] [core:notice] [pid 20249] AH00052: child pid 25933 exit //signal Aborted (6)
//[Mon Jun 03 19:53:48.691727 2013] [core:notice] [pid 20249] AH00052: child pid 25952 exit //signal Aborted (6)

但如果我改为使用 $stmt2=$dbh->prepare("UPDATE ...."); 没有什么奇怪的事情发生,并且语句执行得很好。如果我启用准备仿真,它也没有问题:

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,true);

$stmt->closeCursor()我在执行第一条语句和unset($stmt)(以及它们两个)之后尝试过,产生了同样的崩溃。我正在使用 PHP 5.4.7。为什么会这样?这是一个错误还是一个非常奇怪的功能?

[更新]我从 xampp 切换到 OpenSUSE 12.3 默认 Apache (2.2.22) 和 PHP (5.3.17) 仍然得到相同的错误,但更详细的转储日志: http: //paste2.org/d0BtdOHI

[更新 2]我还确认在使用 MySQL 5.5.27 而不是 MariaDB 5.5.29 作为服务器时会发生这种情况,因此它肯定来自我的脚本并且非常通用(为了以防万一,还要尝试使用 centos 虚拟机这是我的发行版中的一些与 glibc 相关的问题......),发生在不同版本的 apache、mysql 和 php 上,但仍然不知道可能是什么原因......

[更新 3]看来 CentOS 6.4 更好,让我可以毫无问题地运行我的脚本,而且由于它是我在生产中使用的,我想没有什么可担心的。无论如何,我真的很想知道这里发生了什么......

4

1 回答 1

3

我为这次较晚的更新道歉,但我在使用 PDO (Sybase) 时遇到了类似的问题,我可以确认绝对应该避免在不取消设置或设置为 null 的情况下重用语句变量。

在 PHP 中,每当我们覆盖一个变量值时,它首先创建新变量,然后才替换并销毁旧值。在大多数情况下,这不是问题(除了花费双倍的内存来分配单个变量),但是对于语句,它完全不同,因为它不会在创建第二个语句和某些数据库时关闭第一个语句或游标驱动程序不能很好地处理同一 PDO 连接中的多个语句。

根据您使用的驱动程序,PDOStatement::closeCursor()可能不会关闭语句,因此问题仍然存在(在http://www.php.net/manual/en/pdostatement.closecursor.php我们可以看到它取决于驱动程序,否则它将使用不关闭语句的 PDO 默认值)。

所以在这种情况下,unset()两者之间PDO::prepare() 的差异很大:

$stmt=$dbh->prepare("SELECT ....");   
$stmt->execute();
unset($stmt); // or $stmt = null; --> statement is destroyed at PDO
$stmt=$dbh->prepare("UPDATE ....");
于 2013-11-26T23:46:29.110 回答