为什么mysqli_stmt :: store_result在使用MySQLnd驱动程序和libmysql驱动程序时有不同的行为?

时间:2014-08-28 20:42:36

标签: php mysqli

这是一个非常简化的例子来说明我所看到的行为。如果您创建下表并运行以下php脚本,您将获得我正在描述的行为:

<?php
/*
CREATE TABLE Testing (id INT NOT NULL PRIMARY KEY, name VARCHAR(255) NOT NULL);
INSERT INTO Testing VALUES (1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five');
*/

$mysqli = new mysqli($dbhost, $dbuser, $dbpasswd, $dbname);
$stmtQuery = $mysqli->prepare("SELECT id, name FROM Testing WHERE id = ?");
$stmtQuery->bind_result($id, $name);

for ($i=1; $i <= 5; $i++) {
    $stmtQuery->bind_param('i', $i);
    $stmtQuery->execute();
    $stmtQuery->store_result();
    $stmtQuery->fetch();
    $stmtQuery->free_result();

    error_log("$id, $name");
}

$stmtQuery->close();
?>

在使用libmysql作为驱动程序的机器上(在我的情况下为5.3.10),这会产生以下输出:

1, One
2, Two
3, Three
4, Four
5, Five

在使用MySQLnd作为驱动程序(5.3.10和5.4.24)的计算机上,这会产生以下结果:

1, One
1, One
1, One
1, One
1, One

我很难过为什么。我可以看到它的方法,但我想真正理解发生了什么。

  • 如果我删除了store_result()和free_result()调用,我会在所有情况下获得预期的行为。我意识到我在这里的例子没有任何理由做一个mysql store_result(再次,这从现实世界的例子中大大简化了),但我不明白为什么在这里使用它会导致问题。
  • 如果我在循环中移动bind_result语句,它也会解决问题,但我认为在执行类似的操作时,bind_result应该在循环之外。

之所以重要,是因为我们将要迁移到5.5并且5.5以下的默认驱动程序是MySQLnd。如果我们在使用如何以及何时使用由MySQLnd驱动程序工作方式暴露的store_result时出错了,我现在要抓住并修复它,而不是以后。

那么,有什么想法吗?

1 个答案:

答案 0 :(得分:1)

您已正确确定问题是mysqli_stmt::free_result()。这是为什么在PHP中手动关闭并释放mysqli内部资源不是一个好主意的另一个原因。您不需要这样做,让PHP自动处理它。

mysqli_stmt::free_result()在PHP手册中没有很好地记录。此函数执行以下操作:

释放与该语句关联的内部结果存储器,包括缓冲和非缓冲数据以及绑定到该语句的所有变量引用。

这意味着当您调用此函数时,它将取消绑定与bind_result()绑定的变量。 您必须在循环内绑定变量或删除$stmtQuery->free_result() 。由于变量仅绑定到第一个结果,因此它们的值将始终向您显示第一个结果的值。

为什么mysqlnd和libmysqlclient之间有区别

我无法确认是否存在差异,因为我无法使用libmysqlclient访问计算机,但是差异可能来自以下两个原因:

  1. 由于内部原因,用于PHP的MySQL本机驱动程序实现此功能的方式有所不同。

  2. mysqlnd或libmysqlclient存在/有错误。