gpt4 book ai didi

php - Mysql insert if not exists without unique constraint(不想依赖回滚错误)(PHP + PDO)

转载 作者:行者123 更新时间:2023-11-29 04:11:00 25 4
gpt4 key购买 nike

我正在制作一个注册页面。我担心两个用户同时使用相同用户名注册的并发问题(知道这种情况很少见,但讨厌代码中的小缺陷)。

所以我的做法是,检查用户名是否存在,如果不存在,则插入一个新行。我正在使用 PDO

我尝试过的

我正在使用交易,但从我这里的问题 How exactly do transactions with PHP PDO work with concurrency?貌似两个事务可以同时读取

  • 我不认为我可以使用 select...for update 因为我没有更新;事实上,我需要锁定将添加新条目的“假想”行,如果它不存在的话
  • 我尝试用谷歌搜索一些示例,但它们似乎无法处理上述并发问题http://php.about.com/od/finishedphp1/ss/php_login_code_2.htm

解决方案?

我用谷歌搜索并在用户名字段上添加了一个 UNIQUE 约束,但不想依赖 MySQL 错误来回滚事务。我不是专家,但它对我来说并不优雅。 那么有没有办法用纯 MySQL insert if not exists

现在,如果这真的是要走的路,我有几个问题。 如果抛出警告,是否会停止查询?比如它会抛出此处示例中显示的异常 PHP + MySQL transactions examples ?还是只有彻头彻尾的错误才会抛出异常?

还有,这里好像暗示Can I detect and handle MySQL Warnings with PHP?警告会以某种方式显示在 PHP 输出中,但我从未遇到过“可见的 MySQL 错误”。问题不是像我的代码中那样使用 PDO,但我只是想知道。 MySQL错误和警告是否输出html?或者它是否只在我调用 errorInfo() 时才说些什么?

谢谢

最佳答案

更新

If I had two unique fields, and did not want to allow either one to be null (since I know I could set one table to "null-able" and have two queries), is there a way to check which one messed up? Like I want to let the user know if username or email was taken. If I do a single insert, I won't know which one failed

And furthermore, if I have two statements (first insert username, check if failed, then try same for email), I can only detect one error at a time; if the username fails and rolls back, I cannot try to do the same for the email (well it would be redundantish, because even if the email exists I would have to check to see if the first query had failed) Edit: Think it can work if I use nested try...catch statements

我觉得你想多了。您可以为每个错误向用户显示不同的错误,但您实际上一次只能检测到一个错误,因为 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;
}
}

现在的问题是错误消息看起来像这样:

键 THE_KEY_NAME 的重复条目“THE_VALUE_YOU_TRIED_TO_INSERT”

获得更有意义的关于它是哪一列的报告的方法是在创建表时用有意义的东西命名索引,例如:

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`)
);

所以现在您的错误消息将如下所示:

key uk_username 的重复条目“THE_VALUE_YOU_TRIED_TO_INSERT”

key uk_email 的重复条目“THE_VALUE_YOU_TRIED_TO_INSERT”

这很容易解析。

这样做的唯一真正替代方法是在插入之前对表进行选择,以确保值不存在。


如果您使用的是 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;
}
}

关于php - Mysql insert if not exists without unique constraint(不想依赖回滚错误)(PHP + PDO),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11171973/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com