更新
如果我有两个唯一字段,并且不想让任何一个为空(因为我知道我可以将一个表设置为“可空”并有两个查询),有没有办法检查哪一个搞砸了?就像我想让用户知道是否使用了用户名或电子邮件。如果我做一次插入,我不知道哪个失败了
此外,如果我有两个语句(首先插入用户名,检查是否失败,然后对电子邮件尝试相同),我一次只能检测到一个错误;如果用户名失败并回滚,我不能尝试对电子邮件做同样的事情(这将是多余的,因为即使电子邮件存在我也必须检查第一个查询是否失败)编辑:认为它可以如果我使用嵌套的 try...catch 语句,则工作
我想你想多了。您可以为每个错误向用户显示不同的错误,但实际上一次只能检测一个错误,因为 mysql 只会在遇到第一个问题时给您一个错误消息。假设前面的查询(一次插入所有值):
try {
$stmt = $db->prepare($sql);
$stmt->execute(array(
':username' => $username,
':email' => $email,
':password' => $password
));
$db->commit();
} catch (PDOException $e) {
$db->rollBack();
if($e->getCode() == 23000) {
// lets parse the message
if(false !== strpos('email', $e->getMessage())) {
echo 'Email "'. $email . '" already exists';
} else if(false !== strpos('username', $e->getMessage()) {
echo 'Username "'. $username .'" taken';
}
} else {
// not a dupe key rethrow error
throw $e;
}
}
现在的问题是错误消息看起来像:
Duplicate entry 'THE_VALUE_YOU_TRIED_TO_INSERT' for key THE_KEY_NAME
获得更有意义的报告的方法是在创建表时用有意义的东西命名索引,例如:
CREATE TABLE the_table (
`id` integer UNSIGNED NOT NULL AUTO_INCREMENT
`username` varchar(30),
`email` varchar(100),
`password` varchar(32),
PRIMARY KEY (`id`),
UNIQUE KEY `uk_email` (`email`),
UNIQUE KEY `uk_username` (`username`)
);
所以现在您的错误消息将如下所示:
Duplicate entry 'THE_VALUE_YOU_TRIED_TO_INSERT' for key uk_username
或者
Duplicate entry 'THE_VALUE_YOU_TRIED_TO_INSERT' for key uk_email
这很容易解析。
这样做的唯一真正替代方法是在插入之前对表进行选择,以确保值不存在。
如果您使用 PDO,您不应该有 PHP 警告...只是异常,如果未捕获将生成标准 php 错误。如果您已display_errors
关闭,则不会输出到屏幕,只会输出到错误日志。
我认为没有办法insert if not exists
让您重新使用唯一键然后捕获异常:
$db = new PDO($dsn, $user, $pass);
$sql = "INSERT INTO the_table (username, email, etc) VALUES (:username,:email,:password)";
$db->beginTransaction();
try {
$stmt = $db->prepare($sql);
$stmt->execute(array(
':username' => $username,
':email' => $email,
':password' => $password
));
$db->commit();
} catch (PDOException $e) {
$db->rollBack();
if($e->getCode() == 23000) {
// do something to notify username is taken
} else {
// not a dupe key rethrow error
throw $e;
}
}