我正在处理一个将 JobName 列定义为 UNIQUE 的 MySQL 表。如果有人尝试使用数据库中已经存在的 JobName 将新 Job 保存到数据库中,MySQL 会抛出警告。
我希望能够在我的 PHP 脚本中检测到这个警告,就像一个错误一样,并适当地处理它。理想情况下,我想知道 MySQL 抛出了什么样的警告,以便我可以分支代码来处理它。
这可能吗?如果不是,是因为MySQL没有这个能力,PHP没有这个能力,还是两者兼而有之?
我正在处理一个将 JobName 列定义为 UNIQUE 的 MySQL 表。如果有人尝试使用数据库中已经存在的 JobName 将新 Job 保存到数据库中,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
}
显然,使用 en-mass 将非常昂贵,因此您可能需要仔细考虑何时以及如何出现警告(这可能会导致您重构以消除它们)。
当然,您可以省去SELECT @@warning_count
.
首先,您应该关闭警告,这样您的访问者就不会看到您的MySQL错误。其次,当你调用 时mysql_query()
,你应该检查它是否返回 false。如果确实如此,请致电mysql_errno()
以找出问题所在。将返回的数字与此页面上的错误代码相匹配。
看起来这是您要查找的错误号:
错误:1169 SQLSTATE:23000 (ER_DUP_UNIQUE)
消息:由于唯一约束,无法写入表 '%s'
ini_set('mysql.trace_mode', 1)
可能是您正在寻找的东西。
然后可以使用自定义 PHP 错误处理程序处理 PHP 错误,但您也可以关闭显示 php 错误,因为它们通常会记录到日志文件中(取决于您的 php 配置)。
更新以删除有关 errno 函数的内容,我现在意识到这些内容不适用于您的情况......
MySQL 中要警惕 forUPDATE
语句的一件事:mysqli_affected_rows()
即使WHERE
子句匹配行也会返回零,但SET
子句实际上并未更改数据值。我只提到这一点是因为这种行为导致了我曾经看过的系统中的错误——程序员使用该返回值在更新后检查错误,假设零意味着发生了一些错误。这只是意味着用户在单击更新按钮之前没有更改任何现有值。
所以我猜想mysqli_affected_rows()
也不能依靠使用来找到这样的警告,除非你update_time
的表中有一个类似列的东西,在更新时总是会被分配一个新的时间戳值。不过,这种解决方法似乎有点笨拙。
根据您使用的(如果有的话)框架,我建议您自己进行查询以检查作业名称,并为用户创建适当的信息以及表单的其余验证。
根据作业名称的数量,您可以将名称发送到包含表单的视图,并使用 javascript 来告诉用户使用哪个。
如果这对您没有意义,那么总结一下我的观点是:不要设计您的程序和/或用户来尝试做非法的事情并在他们这样做时捕获错误并随后处理它。恕我直言,将系统设计为不产生错误要好得多。将错误保留为实际错误:)
您可以使用 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); }
有可能得到警告,并且使用 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");