如何关闭mysqli-prepared语句中的结果集,但保留该语句-而不缓冲整个结果


How to close the result set in mysqli prepared statement, but keep the statement - without buffering entire result?

我试图在PHP中使用多个已准备好的语句和mysqli驱动程序,但却得到了臭名昭著的错误:

命令不同步;你现在不能运行这个命令

虽然我认为这个数据库API是严重的脑损伤,但我确实理解为什么我会得到错误,正如这个问题所描述的那样。

在这个和我发现的其他各种答案中提供了几个解决方案,我看到的唯一有效的解决方案涉及

$stmt->store_result()

其缓冲整个结果集。

然而,我不想缓冲整个结果集——我想丢弃它,而不使用(大量)内存来存储它!

我所要做的就是创建一个准备好的语句,使用bind_param()bind_result()fetch()来获得一些结果,然后以某种方式关闭结果,这样我以后就可以重用该语句并运行其他查询,直到

我已经尝试了几乎所有的方法来从语句中获得正在使用的实际结果对象,并显式地关闭它,我还尝试了调用next_result(),直到它返回null。这两种解决方案都不能防止出现错误。

那么,如何在fetch()之后关闭结果集并执行其他准备好的语句,而不破坏执行的语句并重新解析查询呢?

$q = $dbc->prepare("SELECT id, typename, storageclass, tablename FROM _dbtype WHERE typename=?");
$q->bind_param("s", $typeName);
$q->bind_result($id,$typeName,$storageClass,$tableName);
$q->execute();
$q->fetch();  // ie.  only once
...  <something that does not destroy $q> ...
$q2 = $dbc->prepare("SELECT id, name FROM _storagetype");

请参阅mysqli_stmt::free_result()
(以及http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-free-result.html提示"如果有一个游标为语句打开,mysql_stmt_free_result()将关闭它。")

<?php
mysqli_report(MYSQLI_REPORT_STRICT|MYSQLI_REPORT_ALL);
$mysqli = new mysqli('localhost', 'localonly', 'localonly', 'test');
if ($mysqli->connect_errno) {
    trigger_error( sprintf('mysqli connect error (%d) %s', $mysqli->connect_errno, $mysqli->connect_error), E_USER_ERROR);
    die;
}
$mysqli->query('CREATE TEMPORARY TABLE sofoo ( id int auto_increment, primary key(id))');
$mysqli->query('INSERT INTO sofoo VALUES (),(),(),(),(),()');

$stmtA = $mysqli->prepare('SELECT id FROM sofoo WHERE id>1');
$stmtB = $mysqli->prepare('SELECT id FROM sofoo WHERE id<10 ORDER BY id DESC');

$stmtA->execute();
$stmtA->bind_result($id);
$stmtA->fetch(); echo $id, PHP_EOL;
$stmtA->free_result(); // without this the script ends with "Fatal error: Uncaught mysqli_sql_exception: Commands out of sync;"
$stmtB->execute();
$stmtB->bind_result($id);
$stmtB->fetch(); echo $id, PHP_EOL;

如果存在多个结果集(即,如果必须使用next_result()),则必须分别为每个结果集调用free_result()