【问题标题】:Can I detect and handle MySQL Warnings with PHP?我可以使用 PHP 检测和处理 MySQL 警告吗?
【发布时间】:2010-09-08 00:51:52
【问题描述】:

我正在处理一个将 JobName 列定义为 UNIQUE 的 MySQL 表。如果有人尝试使用数据库中已有的 JobName 将新 Job 保存到数据库中,MySQL 会抛出警告。

我希望能够在我的 PHP 脚本中检测到这个警告,就像一个错误一样,并适当地处理它。理想情况下,我想知道 MySQL 抛出了什么样的警告,以便我可以分支代码来处理它。

这可能吗?如果不是,是因为MySQL没有这个能力,PHP没有这个能力,还是两者兼而有之?

【问题讨论】:

    标签: php mysql error-handling warnings


    【解决方案1】:

    要在 PHP 本地“标记”警告,需要更改 mysql/mysqli 驱动程序,这显然超出了这个问题的范围。相反,您将不得不基本上检查您对数据库进行的每个查询是否有警告:

    $warningCountResult = mysql_query("SELECT @@warning_count");
    if ($warningCountResult) {
        $warningCount = mysql_fetch_row($warningCountResult );
        if ($warningCount[0] > 0) {
            //Have warnings
            $warningDetailResult = mysql_query("SHOW WARNINGS");
            if ($warningDetailResult ) {
                while ($warning = mysql_fetch_assoc($warningDetailResult) {
                    //Process it
                }
            }
        }//Else no warnings
    }
    

    显然,应用 en-mass 会非常昂贵,因此您可能需要仔细考虑何时以及如何出现警告(这可能会导致您重构以消除它们)。

    供参考,MySQL SHOW WARNINGS

    当然,您可以省去对 SELECT @@warning_count 的初始查询,这样每次执行都会为您节省一个查询,但我将它包括在内是为了书呆子的完整性。

    【讨论】:

    【解决方案2】:

    首先,您应该turn warnings off,这样您的访问者就不会看到您的MySQL 错误。其次,当您调用mysql_query() 时,您应该检查它是否返回false。如果是这样,请致电mysql_errno() 找出问题所在。将返回的数字与this page 上的错误代码匹配。

    看起来这是您要查找的错误号:

    错误:1169 SQLSTATE:23000 (ER_DUP_UNIQUE)

    消息:由于唯一约束,无法写入表“%s”

    【讨论】:

    • 如果我没记错的话,他问的是警告,而不是错误。警告仍然允许查询通过,因此mysql_query 不会返回false。请参阅 iAn 对 PHP 有限警告支持的回答。
    【解决方案3】:
    ini_set('mysql.trace_mode', 1)
    

    可能是您正在寻找的。​​p>

    然后可以使用自定义 PHP 错误处理程序来处理 PHP 错误,但您也可以关闭显示 php 错误,因为它们通常会记录到日志文件中(取决于您的 php 配置)。

    【讨论】:

      【解决方案4】:

      根据您使用的(如果有的话)框架,我建议您自己进行查询以检查作业名称,并为用户创建适当的信息以及表单的其余验证。

      根据作业名称的数量,您可以将名称发送到包含表单的视图,并使用 javascript 告诉使用哪个。

      如果这对您没有意义,那么总结一下我的观点是:不要设计您的程序和/或用户来尝试做非法的事情并在他们这样做时捕获错误并随后处理它。恕我直言,将系统设计为不产生错误要好得多。将错误保留为实际错误:)

      【讨论】:

        【解决方案5】:

        已更新以删除我现在意识到不适用于您的情况的有关 errno 函数的内容...

        在 MySQL 中要警惕 UPDATE 语句的一件事:即使 WHERE 子句匹配行,mysqli_affected_rows() 也会返回零,但 SET 子句实际上并未更改数据值。我只提到这一点是因为这种行为导致了我曾经看过的系统中的错误——程序员使用该返回值在更新后检查错误,假设零意味着发生了一些错误。这只是意味着用户在单击更新按钮之前没有更改任何现有值。

        所以我想也不能依靠使用mysqli_affected_rows() 来找到此类警告,除非您的表中有类似update_time 的列,在更新时总是会分配一个新的时间戳值。不过,这种解决方法似乎有点笨拙。

        【讨论】:

          【解决方案6】:

          您可以使用 mysqli 语句错误号检测唯一键违规。 mysqli 语句返回错误 1062,即 ER_DUP_ENTRY。您可以查找错误 1062 并打印合适的错误消息。如果您还想打印列 (jobName) 作为错误消息的一部分,那么您应该解析语句错误字符串。

          if($stmt = $mysqli->prepare($sql)){ $stmt->bind_param("sss", $名称, $identKey, $域名); $stmt->执行(); if($mysqli->affected_rows != 1) { //这将返回errorno 1062 trigger_error('mysql错误>>'.$stmt->errno.'::'.$stmt->error, E_USER_ERROR); 退出(1); } $stmt->关闭(); } 别的 { trigger_error('mysql错误>>'.$mysqli->errno.'::'.$mysqli->error,E_USER_ERROR); }

          【讨论】:

            【解决方案7】:

            使用 mysqli 可以获得警告,并且比使用 mysql 更有效。

            这里是 php.net 上的手册 page 中为属性 mysqli->warning_count 建议的代码:

            $mysqli->query($query);
            
            if ($mysqli->warning_count) {
                if ($result = $mysqli->query("SHOW WARNINGS")) {
                    $row = $result->fetch_row();
                    printf("%s (%d): %s\n", $row[0], $row[1], $row[2]);
                    $result->close();
                }
            }
            

            【讨论】:

              【解决方案8】:

              关于禁止显示警告的注意事项:通常,阻止显示警告不是一个好主意,因为您可能会遗漏一些重要的东西。如果您出于某种原因绝对必须隐藏警告,您可以通过在声明前放置@ 符号来单独执行此操作。这样您就不必关闭所有警告报告,并且可以将其限制为特定实例。

              例子:

               // this suppresses warnings that might result if there is no field titled "field" in the result
               $field_value = @mysql_result($result, 0, "field");
              

              【讨论】:

              • 听起来用户希望能够捕捉到错误,而不是抑制它。
              • 使用ini_set('display_errors',0); 是一个更好的主意(更好的是,把它放在你的php.ini 中),这样用户就不会看到任何可能构成安全风险的东西。除此之外,我建议确保将error_log 设置为可写文件并设置error_reporting = -1,以便了解所有潜在问题。
              猜你喜欢
              • 1970-01-01
              • 2010-10-14
              • 2010-09-21
              • 1970-01-01
              • 2010-12-06
              • 2011-01-12
              • 2020-07-31
              • 2023-03-14
              相关资源
              最近更新 更多