这有点类似于这个问题:
PHP MySQL INSERT fails due to unique constraint
但我有不同的转折。假设我有一个只有一列的表格。列的名称是“title”,它有一个唯一的约束。
首先我插入一行title =“something”。下次我尝试插入“某事”时,由于唯一的键约束(这很好),它将失败。我想做的是让它失败,并检查mysql提供的错误代码,以确保它由于唯一的键约束而失败。 (即让数据库处理唯一性,我只是处理错误代码并在结果返回时告诉用户标题已存在)。
有办法做到这一点吗?
答案 0 :(得分:17)
现在是2015年,没有理由不使用PHP的PDO实施:
http://php.net/manual/en/book.pdo.php
适当的,现代的," OO"用于检测和处理由于键约束违反而导致的插入失败的方法如下:
try {
//PDO query execution goes here.
}
catch (\PDOException $e) {
if ($e->errorInfo[1] == 1062) {
//The INSERT query failed due to a key constraint violation.
}
}
PDOException对象还有一个 lot 更多关于错误的特定性质的说法(似乎比一个人可能想要或需要的更多细节)。
答案 1 :(得分:12)
http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
http://php.net/manual/en/function.mysql-errno.php
过去我必须这样做,这并不好玩:
if( mysql_errno() == 1062) {
// Duplicate key
} else {
// ZOMGFAILURE
}
关于编程风格的说明(jensgram来自this的积分答案)
你应该总是试图避免使用magic numbers。相反,您可以将已知错误代码(1062
)分配给常量(例如MYSQL_CODE_DUPLICATE_KEY
)。这将使您的代码更易于维护,因为if
语句中的条件在1062
的含义从内存中消失后的几个月内仍然可读:)
答案 2 :(得分:2)
我相信重复键的错误代码是1586.如果您尝试执行查询然后失败,请使用mysql_errno() / mysqli::errno()检查错误代码并将其与1586进行比较,应该这样做。如果它不是1586,请在查询后回显错误代码,检查它实际是什么。
答案 3 :(得分:2)
为什么不先进行选择以查看该条目是否已存在。或者通过使用INSERT ON DUPLCATE KEY UPDATE完全抑制错误,甚至使用mysql IGNORE关键字。为什么故意导致错误?
答案 4 :(得分:2)
主题对于PHP / Mysql用户很感兴趣,所以让我概述一个解决方案。 请注意
假设您有一个表单 - 您有一个字段“名称”
添加一个像 -
这样的唯一约束alter table wb_org add constraint uniq_name unique(name);
表单处理程序脚本应该将数据传递给DB层,如果有任何错误,DB层会将其指示为DBException(由我们定义的异常)。我们将代码发送到try-catch块中的DB层(仅显示相关代码)
try{
....
$organizationDao = new \com\indigloo\wb\dao\Organization();
$orgId = $organizationDao->create($loginId,$fvalues["name"]) ;
....
} catch(UIException $ex) {
....
// do UI exception handling
} catch(DBException $ex) {
$errors = array();
$code = $ex->getCode();
$message = $ex->getMessage();
// look for code 23000, our constraint name and keyword duplicate
// in error message thrown by the DB layer
// Util::icontains is just case-insensitive stripos wrapper
if( ($code == 23000)
&& Util::icontains($message,"duplicate")
&& Util::icontains($message,"uniq_name")) {
$errors = array("This name already exists!");
} else {
// Not sure? show generic error
$errors = array(" Error: doing database operation!") ;
}
// log errors
Logger::getInstance()->error($ex->getMessage());
Logger::getInstance()->backtrace($ex->getTrace());
// store data in session to be shown on form page
$gWeb->store(Constants::STICKY_MAP, $fvalues);
$gWeb->store(Constants::FORM_ERRORS,$errors);
// go back to form
$fwd = base64_decode($fUrl);
header("Location: " . $fwd);
exit(1);
}catch(\Exception $ex) {
// do generic error handling
}
请注意,您必须找到适合您情况的ex-> getCode()。与上面一样,PDO层实际上是将SQLSTATE 23000作为ex->代码(其中实际的mysql错误代码为1062)。代码也可能因DB而异。同样的方式ex->消息也可以变化。最好将这个检查包装在一个地方并使用配置文件进行操作。
static function create($loginId, $name) {
$dbh = NULL ;
try {
$dbh = PDOWrapper::getHandle();
//Tx start
$dbh->beginTransaction();
...
// do DB operations
//Tx end
$dbh->commit();
$dbh = null;
} catch(\Exception $ex) {
$dbh->rollBack();
$dbh = null;
throw new DBException($ex->getMessage(),$ex->getCode());
}
提取会话中设置的错误消息并将其显示在表单上。
<?php
namespace com\indigloo\exception {
class DBException extends \Exception {
public function __construct($message,$code=0, \Exception $previous = null) {
// PDO exception etc. can return strange string codes
// Exception expects an integer error code.
settype($code,"integer");
parent::__construct($message,$code,$previous);
}
}
}
?>
static function icontains($haystack, $needle) {
return stripos($haystack, $needle) !== false;
}
从mysqli获取错误代码和错误消息,并从DB层抛出DBException 以相同的方式处理DBException。
我写这篇文章时没有任何实际操作代码的经验。如果您不同意,请告诉我。另外,如果您有更好的计划,请分享。如果你只是想要一个catch-it-all泛型处理程序,那么是的。
我使用trigger_error和error_handlers找到的问题是
我没有太多处理错误代码的经验(我已经在例外情况下提出过) - 所以也许其他人可以启发我们。
代码示例来自我的公共github repo https://github.com/rjha/website - 我正在编写的代码用于创建一个网站构建器,以便从同一个数据库启动数千个站点。上面的代码用于检查网站的唯一名称。
答案 5 :(得分:1)
来自mysql_errno
函数的PHP Documentation:
Returns the error number from the last MySQL function,
or 0 (zero) if no error occurred.
此外,从MySQL Documentation约束违规错误,错误代码893对应于:
Constraint violation e.g. duplicate value in unique index
所以,我们可以写这样的东西来做这项工作:
if (!$result) {
$error_code = mysql_errno();
if ($error_code == 893) {
// Duplicate Key
} else {
// Some other error.
}
}
答案 6 :(得分:0)
If you know some SQL, try this solution (tested)
$username = "John";
$stmt = $pdo->prepare("
INSERT INTO users (
username
) SELECT * FROM (
SELECT :username
) AS compare
WHERE NOT EXISTS (
SELECT username
FROM users
WHERE username = :username
) LIMIT 1;
");
$stmt->bindParam(":username", $username);
if ($stmt->execute()) {
if ($stmt->rowCount() == 0) {
echo "Dublicate Username, ".$username." already exists.";
} else {
echo $username." not in use yet.";
}
}