我可以使用PHP检测和处理MySQL警告吗?

时间:2020-03-05 18:48:44  来源:igfitidea点击:

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

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

这可能吗?如果不是,是否是因为MySQL不具备此功能,PHP不具备此功能,还是两者兼而有之?

解决方案

回答

首先,我们应该关闭警告,以便访问者看不到MySQL错误。其次,当我们调用mysql_query()时,应该检查它是否返回false。如果是这样,请调用mysql_errno()以找出问题所在。使返回的数字与本页上的错误代码相匹配。

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

Error: 1169 SQLSTATE: 23000 (ER_DUP_UNIQUE)
  
  Message: Can't write, because of unique constraint, to table '%s'

回答

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

MySQL中需要注意的一件事是UPDATE语句:即使WHERE子句与行匹配,mysqli_affected_rows()仍将返回零,但是SET子句实际上并未更改数据值。我之所以仅提及这一点,是因为该行为导致了我曾经查看过的系统中的错误-程序员使用该返回值来检查更新后的错误,假设为零表示发生了某些错误。这仅表示用户在单击更新按钮之前未更改任何现有值。

因此,我猜也不能依赖于使用mysqli_affected_rows()来查找此类警告,除非表中有类似update_time列的内容,并且在更新时总会为其分配新的时间戳记值。但是,这种解决方法似乎有点麻烦。

回答

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

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

如果这对我们没有意义,那么总结一下我是这样的:不要设计程序和/或者用户尝试做非法的事情,并在执行错误时捕获错误并加以处理。恕我直言,将系统设计为不产生错误会更好。将错误保留为实际错误:)

回答

为了使警告"标记"为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
}

显然,进行批量处理将非常昂贵,因此我们可能需要仔细考虑警告的产生时间和方式(这可能会导致我们重构以消除它们)。

作为参考,MySQL SHOW WARNINGS

当然,我们可以省去对SELECT @@ warning_count的初始查询,这样可以为每次执行节省一个查询,但是出于学究的完整性,我将其包括在内。

回答

我们可以使用mysqli语句错误编号来检测唯一键冲突。 mysqli语句返回错误1062,即ER_DUP_ENTRY。我们可以查找错误1062并打印适当的错误消息。如果我们还希望将列(jobName)打印为错误消息的一部分,则应分析语句错误字符串。

if($stmt = $mysqli->prepare($sql)){
            $stmt->bind_param("sss",
            $name,
            $identKey,
            $domain);

            $stmt->execute();
            if($mysqli->affected_rows != 1)  {
                        //This will return errorno 1062
                trigger_error('mysql error >> '.$stmt->errno .'::' .$stmt->error, E_USER_ERROR);
                exit(1);
            }
            $stmt->close();
        } else {

            trigger_error('mysql error >> '. $mysqli->errno.'::'.$mysqli->error,E_USER_ERROR);
        }

回答

使用mysqli比使用mysql更有效地获得警告。

这是php.net手册页上建议的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();
    }
}