我可以使用 PHP 检测和处理 MySQL 警告吗?
-
09-06-2019 - |
题
我正在处理一个将 JobName 列定义为 UNIQUE 的 MySQL 表。如果有人尝试使用数据库中已有的 JobName 将新作业保存到数据库,MySQL 会发出警告。
我希望能够在我的 PHP 脚本中检测到此警告,就像错误一样,并进行适当的处理。理想情况下,我想知道 MySQL 抛出了什么样的警告,以便我可以分支代码来处理它。
这可能吗?如果没有,是因为MySQL没有这个能力,PHP没有这个能力,还是两者都有?
解决方案
对于本地“标记”到 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 显示警告
当然,您可以省去最初的查询 SELECT @@warning_count
, ,这将为您节省每次执行的查询,但我将其包含在内是为了迂腐的完整性。
其他提示
首先,你应该 关闭警告 这样您的访客就看不到您的 MySQL 错误。第二,当你打电话时 mysql_query()
, ,你应该检查它是否返回 false。如果是这样,请致电 mysql_errno()
找出问题所在。将返回的数字与错误代码相匹配 这一页.
看起来这就是您要查找的错误号:
错误:第1169章23000 (ER_DUP_UNIQUE)
信息:由于唯一约束,无法写入表“%s”
ini_set('mysql.trace_mode', 1)
可能就是您正在寻找的。
然后可以使用自定义 PHP 错误处理程序来处理 PHP 错误,但您也可以关闭显示 php 错误,因为它们通常会记录到日志文件中(取决于您的 php 配置)。
根据您使用的框架(如果有),我建议您执行查询来自己检查作业名称,并为用户创建正确的信息以及表单的其余验证。
根据作业名称的数量,您可以将名称发送到包含表单的视图,并使用 javascript 告诉用户所采用的名称。
如果这对您来说没有意义,那么总结一下我的观点是:不要将您的程序和/或用户设计为尝试执行非法操作并在执行时捕获错误并进行处理。恕我直言,最好将系统设计为不产生错误。将错误保留为实际错误:)
更新以删除有关 errno 函数的内容,我现在意识到这些函数不适用于您的情况......
MySQL 中需要警惕的一件事 UPDATE
声明: mysqli_affected_rows()
即使 WHERE
子句匹配行,但是 SET
子句实际上并没有改变数据值。我之所以提到这一点,是因为这种行为导致了我曾经查看过的系统中的错误 - 程序员在更新后使用该返回值来检查错误,假设零意味着发生了某些错误。这只是意味着用户在单击更新按钮之前没有更改任何现有值。
所以我想使用 mysqli_affected_rows()
也不能指望找到这样的警告,除非你有类似的东西 update_time
表中的列在更新时将始终分配新的时间戳值。不过,这种解决方法似乎有点笨拙。
您可以使用 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();
}
}
关于抑制警告的注意事项:一般来说,阻止显示警告并不是一个好主意,因为您可能会错过一些重要的内容。如果出于某种原因您绝对必须隐藏警告,您可以通过放置 @
在声明前面签名。这样您就不必关闭所有警告报告,并且可以将其限制为特定实例。
例子:
// this suppresses warnings that might result if there is no field titled "field" in the result
$field_value = @mysql_result($result, 0, "field");