以下是我的代码示例
$mysqli = new mysqli("localhost", "root", "123", "temp");
var_dump($mysqli);
$mysqli->begin_transaction();
$sql1 = "insert into test (Name) values ('pratik5');";
$sql1 .= "insert into test (Name) values ('pratik6');";
$test = $mysqli->multi_query($sql1);
$mysqli->commit();
答案 0 :(得分:3)
$mysqli->multi_query($sql1);
$mysqli->commit(); // This will result in a "Commands out of sync; you can't run this command now" error.
以上内容与
相同:$mysqli->multi_query($sql1);
$mysqli->query("commit"); // This will result in a "Commands out of sync; you can't run this command now" error.
无论您输入什么$mysqli->query("...");
,即使使用简单的"Commands out of sync"
,它也会导致SELECT 1
错误;
此错误的原因是因为->commit()
操作运行单个查询(commit;
)。但是,以前的查询的结果尚未读取。
当使用单个query()
操作时,MySQL服务器将使用取决于查询语句的响应帧进行应答。
使用multi_query()
时,在MySQL通信协议级别发生以下情况:
multi_query()
。如果要使用multi_query()
,则必须将start transaction
/ commit
操作作为其一部分:
$mysqli = new mysqli("localhost", "root", "123", "temp");
$sql1 = "start transaction;"; // $mysqli->begin_transaction() is a convenience function for simply doing this.
$sql1 .= "insert into test (Name) values ('pratik5');";
$sql1 .= "insert into test (Name) values ('pratik6');";
$sql1 .= "commit;"; // $mysqli->commit() is a convenience function for simply doing this.
$mysqli->multi_query($sql1);
/* As in "Solution 2", if you plan to perform other queries on DB resource
$mysqli after this, you must consume all the resultsets:
// This loop ensures that all resultsets are processed and consumed:
do {
$mysqli->use_result();
}
while ($mysqli->next_result());
*/
$mysqli = new mysqli("localhost", "root", "123", "temp");
$mysqli->begin_transaction();
$sql1 = "insert into test (Name) values ('pratik5');";
$sql1 .= "insert into test (Name) values ('pratik6');";
$mysqli->multi_query($sql1);
// This loop ensures that all resultsets are processed and consumed:
do {
$mysqli->use_result();
}
while ($mysqli->next_result());
// Now that all resultsets are processed, a single query `commit;` can happen:
$mysqli->commit();
MySQL参考:"Commands out of sync"。
答案 1 :(得分:1)
您不应该使用多重查询。重写您的代码如下
$mysqli->begin_transaction();
$mysqli->query("insert into test (Name) values ('pratik5')");
$mysqli->query("insert into test (Name) values ('pratik6')");
$mysqli->commit();
或者,对于现实插页,
$mysqli->begin_transaction();
$stmt = $mysqli->prepare("insert into test (Name) values (?)");
$stmt->bind_param("2", $name);
$name = 'pratik5';
$stmt->execute();
$name = 'pratik6';
$stmt->execute();
$mysqli->commit();
答案 2 :(得分:0)
首先,在示例中您显示了您不应该使用multi_query()
。您有两个单独的语句,应分别执行。参见Your Common Sense's answer
multi_query()
应该很少使用。仅当您已经拥有一个由多个查询组成的字符串时,该字符串才是您绝对信任的情况,才应使用它。永远不要允许变量输入multi_query()
!
commit()
在multi_query()
之后不起作用?实际上,MySQL确实在commit()
上抛出了错误,但是mysqli不能将错误作为异常抛出。我不知道是错误还是技术限制。如果手动检查$mysqli->error
属性,则会看到错误。您应该看到如下错误:
命令不同步;您现在不能运行此命令
但是,一旦调用use_result()
或store_result()
,就会正确引发异常。
$mysqli->multi_query(/* SQLs */);
$mysqli->commit();
$r = $mysqli->use_result(); // Uncaught mysqli_sql_exception: Commands out of sync; you can't run this command now
MySQL之所以说命令不同步,是因为每个MySQL会话一次只能执行一个命令。但是,multi_query()
通过单个命令将整个SQL字符串发送给MySQL,让我们让MySQL异步运行查询。在将控件传递回PHP脚本之前,PHP最初将等待第一个产生非DML查询(非INSERT,UPDATE或DELETE)的结果集完成运行。这使MySQL可以在服务器上运行其余的SQL并缓冲结果,而您可以使用PHP进行其他一些操作并稍后收集结果。在迭代以前的异步查询的所有结果之前,您不能在同一连接上运行另一个SQL命令。
正如另一个答案所指出的,commit()
将尝试在同一连接上执行另一个命令。之所以出现不同步错误,是因为您还没有完成处理multi_query()
命令。
每个异步查询都应在mysqli中紧跟一个阻塞循环。阻塞循环将遍历服务器上所有已执行的查询,并一步一步地获取结果,然后可以在PHP中进行处理。这是此类循环的示例:
do {
$result = $mysqli->use_result();
if ($result) {
// process the results here
$result->free();
}
} while ($mysqli->next_result()); // Next result will block and wait for next query to finish
$mysqli->store_result(); // Needed to fetch the error as exception
即使您知道查询不会产生任何结果集,也必须始终具有阻塞循环。
远离multi_query()
!大多数时候,有一种更好的执行SQL文件的方法。如果您将查询分开,则不要将它们串联在一起,而是自己执行。
如果您确实需要使用multi_query()
,并且希望将其包装在事务中,则必须将commit()
放在阻塞循环之后。您必须先迭代所有结果,然后才能执行COMMIT;
命令。
$mysqli->begin_transaction();
$sql1 = "insert into test (Name) values ('pratik5');";
$sql1 .= "insert into test (Name) values ('pratik6');";
$test = $mysqli->multi_query($sql1);
// $mysqli->commit();
do {
$result = $mysqli->use_result();
if ($result) {
// process the results here
$result->free();
}
} while ($mysqli->next_result());
$mysqli->store_result(); // To fetch the error as exception
$mysqli->commit();
当然要查看任何mysqli错误,您需要启用例外模式。只需将这一行放在new mysqli()
之前:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);