我可以使用PHP检测和处理MySQL警告吗?
我正在处理将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(); } }