【问题标题】:How does mysqli::multi_query affect mysqli_stmt::prepare when only CREATE table is executed in multi_query?当 multi_query 中只执行 CREATE 表时,mysqli::multi_query 如何影响 mysqli_stmt::prepare?
【发布时间】:2021-11-25 17:48:34
【问题描述】:

我在 php 中有一个非常简单的代码来创建一个表,然后使用用户输入将值存储在表中,如下所示:

   $sql = 'CREATE TABLE admins (
      id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      username VARCHAR(30) NOT NULL,
      password VARCHAR(30) NOT NULL,
      reg_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    );';  
    $result = $conn->query($sql);
    if($result) {              
      $stmt = $conn->prepare("INSERT INTO `admins` (username, password) VALUES (?, ?)");         
      $stmt->bind_param("ss", $admin_name, $admin_pass1);
      $stmt->execute()

这很顺利,因为...然后我需要一次创建两个表,我将代码更改为:

    $sql = 'CREATE TABLE admins (
      id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      username VARCHAR(30) NOT NULL,
      password VARCHAR(30) NOT NULL,
      reg_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    );
    CREATE TABLE categories (
      id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      datetime2 VARCHAR(50) NOT NULL, 
      name VARCHAR(100) NOT NULL,
      creatorname VARCHAR(200) NOT NULL
    );
    ';  
    $result = $conn->multi_query($sql);
    if($result) {
      //$result->free(); //$result is a boolean !!
      $stmt = $conn->prepare("INSERT INTO `admins` (username, password) VALUES (?, ?)");
      
      //var_dump($conn->error);
      $stmt->bind_param("ss", $admin_name, $admin_pass1);
      //here I get error, "can't bind to boolean"// ($stmt is false)
      $stmt->execute();

经过研究,我发现要执行多个查询,必须首先清除(获取?)结果缓冲区,否则您会收到错误 Commands out of syncphp.net quotes:

MYSQLI_USE_RESULT - 返回一个带有无缓冲结果集的 mysqli_result 对象。只要有挂起的记录等待获取,连接线就会忙,所有后续调用都会返回错误 Commands out of sync。为避免该错误,必须从服务器获取所有记录,或者必须通过调用 mysqli_free_result() 丢弃结果集。

问题一:我们是否需要在默认用法($result_mode = MYSQLI_STORE_RESULT)中获取记录以使用mysqli::query 执行多个查询?

对这种情况的另一个警告是,在我的情况下,来自$result = $conn->multi_query($sql);$result 是一个布尔值,因为正在使用的查询是非 DML。现在我认为$conn->prepare(...) 失败了,因为我需要先获取multi_query 的结果,但是由于我使用的是非dml 查询,所以没有任何结果可以获取。我不能使用mysqli_result::free 或类似mysqli_next_result()fetch() 的东西,因为$result 不是对象!

为了让我更加困惑,我的第一个代码运行没有错误,我只使用了mysqli::query(),然后连续使用了$conn->prepare(),没有清除任何缓冲区。所以,

问题 2: 幕后发生了什么?为什么我在使用$conn->multi_query 后不能使用$conn->prepare?如果有任何缓冲区要清除,那么我该如何清除它们或为什么有任何缓冲区没有结果显示?

【问题讨论】:

  • 只需执行 2 个查询,将创建的 2 个拆分为 2 个字符串并为每个运行一次 mysqli_query()
  • Q2:因为您必须正确使用来自 multi_query 的结果集,而您没有
  • @RiggsFolly 可能你误读了我的问题,我使用mysqli_multi_query 进行多个查询。
  • 我做了,但基本上 multi_query 使用起来很痛苦,所以请参阅已编辑的评论 1
  • 是的,只需调用 mysqli_query() 两次并以这种方式创建两个表。简化问题。

标签: php mysqli


【解决方案1】:

只需使用对mysqli_query() 的两次单独调用来执行它们。不要使用mysqli_multi_query()

当您使用mysqli_multi_query() 时,您可以一次性向 MySQL 服务器发送多个查询。 MySQL 不会并行执行它们。事实上,MySQL 只会执行第一个并将结果返回给 PHP。然后由 PHP 代码负责检索第一个结果 (store_result()) 并要求 MySQL 发送下一个结果 (next_result())。见Multiple Statements on php.net

一旦 PHP 完整获取当前待处理的结果,MySQL 将开始执行下一个查询。这是批量发送查询的唯一微小性能优势。 PHP 可以在 MySQL 准备下一个结果时并行工作。

$mysqli->multi_query('SELECT 1;SELECT SLEEP(5)');
// fetch the pending result. This let's MySQL start working on the next one
$res1 = $mysqli->store_result();

// PHP does something time consuming in the meantime
sleep(2);

// Tell MySQL to send the next result. PHP waits here...
$mysqli->next_result();
$res2 = $mysqli->store_result();

所有查询都会产生结果!对于某些查询,您可能无法在 PHP 中获得 mysqli_result 对象,但这并不意味着 MySQL 没有发送任何响应。当使用mysqli_multi_query() 时,您必须将这些结果获取到 PHP。否则,线路将占线,您将无法在同一连接上发送任何其他内容。

使用mysqli_multi_query() 非常麻烦,几乎没有任何好处。如果您发现自己需要使用它,那么很可能您做错了什么。只需逐个发送每个查询或使用准备好的语句。

附:不要忘记启用 mysqli 错误报告,否则您对整个功能的体验会更差。 How to get the error message in MySQLi?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-22
    • 2015-04-08
    • 2019-07-16
    • 1970-01-01
    • 2012-01-25
    • 2016-08-07
    • 1970-01-01
    • 2020-11-29
    相关资源
    最近更新 更多