【问题标题】:How do I ensure I caught all errors from MySQLi::multi_query?如何确保从 MySQLi::multi_query 中捕获所有错误?
【发布时间】:2011-11-15 18:09:30
【问题描述】:

docs for multi_query 说:

如果第一条语句失败,则返回 FALSE。要从其他语句中检索后续错误,您必须先调用 mysqli_next_result()。

docs for next_result 说:

成功时返回 TRUE,失败时返回 FALSE。

最后,multi_query 文档中发布的示例使用来自next_result 的返回值来确定何时不再有查询;例如停止循环:

<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$query  = "SELECT CURRENT_USER();";
$query .= "SELECT Name FROM City ORDER BY ID LIMIT 20, 5";

    /* execute multi query */
    if ($mysqli->multi_query($query)) {
        do {
            /* store first result set */
            if ($result = $mysqli->store_result()) {
                while ($row = $result->fetch_row()) {
                    printf("%s\n", $row[0]);
                }
                $result->free();
            }
            /* print divider */
            if ($mysqli->more_results()) {
                printf("-----------------\n");
            }
        } while ($mysqli->next_result()); // <-- HERE!
    }

    /* close connection */
    $mysqli->close();
    ?>

我不知道提供的查询数量,也不知道我将要执行的 SQL。因此,我不能只将查询数与返回结果数进行比较。但是,如果第三个查询是损坏的查询,我想向用户显示一条错误消息。但我似乎没有办法判断 next_result 失败是因为没有更多的查询要执行,还是因为 SQL 语法有错误。

如何检查所有查询是否有错误?

【问题讨论】:

  • 错误处理会有所不同,具体取决于您配置 mysqli_report();你是怎么配置的?
  • @Billy Oneal,multi_query 只生成一个错误,因为它在遇到第一个语法错误时中断。 multi_query 完成后,检查错误。这将是“是的,有一个错误”或“不,没有错误”的问题。供您参考:stackoverflow.com/questions/14715889/…
  • @mickmackusa ,我试过了,用 mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);如果我使用带有 INSERT 命令的 SQL 引用不存在的表,它会给我与查询成功一样的结果。我得到的结果来自 $mysqli->error,它里面有以下文本: Commands out of sync;你现在不能运行这个命令”。
  • @YevgeniyAfanasyev,您对 mysqli_report() 的使用听起来像是真正的蠕虫罐头。我不使用它,但我读到 @php.net/manual/en/function.mysqli-report.php 它适用于“异常”而不是正常的错误消息——这一定是导致 multi_query() 混淆的原因。我猜想因为没有结果集或影响行的东西也没有错误,所以随后的 mysqli 函数被调用是徒劳的。是的?我担心需要一个带有自定义断点的更复杂的解决方案来适应您的 mysqli_report() 技术。一定要分享。
  • @mickmackusa,是的 mysqli_report 从 mysqli 的错误中排除异常。这是更好的手册nusphere.com/kb/phpmanual/function.mysqli-report.htm 如果你没有使用它的任何特殊配置,或者没有,没关系,你不能“检查错误”,就像你之前提到的那样查看是否发生错误,如果你不'不知道应该影响多少行以及多查询脚本中有多少查询。缺乏信息是问题的一部分。

标签: php mysql mysqli


【解决方案1】:

尽管文档中有代码示例,但更好的方法可能是这样的:

if ($mysqli->multi_query(...)) {
  do {
    // fetch results

    if (!$mysqli->more_results()) {
      break;
    }
    if (!$mysqli->next_result()) {
      // report error
      break;
    }
  } while (true);
}

【讨论】:

  • 我尝试使用 "while ($mysqli->more_results()) {...}" 但它变成了一个无限循环
  • 我怎样才能得到你有// report error的确切错误? $mysqli-&gt;error 未设置,因为 next_result() 在遇到错误之前返回 FALSE
  • next_result() 文档说它在错误时返回 false,但是 more_results() 返回 true 但 next_result() 不返回 true 的情况应该很少见。
  • @BillKarwin 我看不出您的回答如何帮助从 MySQLi::multi_query 捕获所有错误,或检查所有查询是否有错误。详情请看我的回答。我认为自从您将答案放在这里后,问题已经改变了。
【解决方案2】:

无法捕获所有错误,请查看您使用的示例(来自here

这个例子中只有“select”语句,这在多语句脚本中并不常见。

如果您将“插入”、“更新”、“删除”或至少“设置” - 它的工作方式会有所不同。

"multi_query" - 如果第一条语句失败,则返回 FALSE。第一条声明——这是我们所能控制的。所有随后的陈述都是谜。如果它不是“select”语句 - 它会在“$mysqli->store_result();”上给出错误我们永远不知道它是否成功。

但是

如果您的 SQL 脚本位于“START TRANSACTION; ... commit;”中包装器,你可以肯定——如果有什么失败,一切都会失败。这很好,这有助于我们查看是否“全部失败”。

为此,只需在“插入-更新”脚本的末尾添加一点“选择”,如果最后一条语句返回数据-所有脚本都成功完成。

使用类似的 SQL:

START TRANSACTION;    
  set @q=1;
  select "success" as response from dual;
commit;

PHP函数:

function last_of_multi_query ($mysqli, $query) {
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); //After that all mysql errors will be transferred into PHP exceptions.
    $mysqli->multi_query($query);               
    do { null; } while($mysqli->next_result());
    $result = $mysqli->store_result();
    if (!$result){
        throw new Exception('multi_query failed');
    }
    return $result;
}// end function

【讨论】:

  • 到目前为止,这应该被标记为最佳答案。让我惊讶的是没有人评论它。
  • @ Marcovecchio,我不认为这应该被标记为最佳答案,因为不是每个使用 mysqli_multi_query 的人都在使用 mysqli_report——更重要的是,OP 不要求使用 mysqli_report()。这个OP的标题有点欺骗性; multi_query 旨在在其第一个 mysqli 错误时中断。如果您需要运行后续查询,无论先前查询的错误数量如何,我认为我建议您不要使用 multi_query。
  • 第二个 - 是 - 如果您需要运行后续查询而不考虑先前的查询 - 不要使用 multi_query。但问题是关于 multi_query。
【解决方案3】:

Bill Karwin 的回答在我看来并不是很有说服力。当 do while 循环已经设置为处理断点时,编写单独的条件中断似乎很奇怪。

我没有测试过下面的sn-p,但是你应该可以从中得到必要的结果和错误:

$queries["CURRENT_USER"]="SELECT CURRENT_USER()";
$queries["CITY_NAME"]="SELECT Name FROM City ORDER BY ID LIMIT 20, 5";

if(mysqli_multi_query($mysqli,implode(';',$queries))){
    do{
        list($current_table,$current_query)=each($queries);
        if($current_table!="CURRENT_USER"){
            printf("-----------------\n");
        }
        if($result=mysqli_store_result($mysqli)){
            if(mysqli_num_rows($result)<1){
                echo "<p>Logic Error @ $current_table Query<br>$current_query</p>";
            }else{
                while($row=mysqli_fetch_row($result)){
                    printf("%s\n",$row[0]);
                }
            }
            mysqli_free_result($result);
        }
    } while(mysqli_more_results($mysqli) && mysqli_next_result($mysqli));
}else{
    list($current_table,$current_query)=each($queries);
}
if($error=mysqli_error($mysqli)){
    echo "<p>Syntax Error @ $current_table Query<br>$current_query<br>Error: $error</p>";
}

【讨论】:

  • 我同意你对比尔回答的立场,但你的建议并不公平。仅当您将所有单查询分开时,它才会起作用。如果你要把它们分开,你最好用 $mysqli->query($query); 单独运行它们。并避免使用 $mysqli->multi_query($query); -- 确保您已发现所有错误。但这不是问题。
  • @YevgeniyAfanasyev,我的建议没有考虑到 mysqli_report() 的使用(正如我在本页的另一条评论中提到的那样)。我相信您的过程的主要障碍是在出现错误时告诉相关的 mysqli 函数。看看@stackoverflow.com/questions/18457821/…“你的常识”已经对此进行了调查(如果你想给他发消息,总是有意见。)ps。看起来他失去了所有的声望点——他并不总是和别人相处得很好:)
  • 感谢您指出 mysqli_report() 错误,但这不是我在之前评论中的意思。我说“你的答案不合适”,因为问题是关于“对 SQL 一无所知”。
  • 我将停止在此线程上讨论您的困境。我的 sn-p 超越了 OP 的解决方案。
猜你喜欢
  • 1970-01-01
  • 2015-04-08
  • 2016-12-07
  • 2018-09-22
  • 2019-11-16
  • 2015-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多