处理来自不同用户的并发 MySQL 查询

发布于 2025-01-03 20:27:34 字数 443 浏览 1 评论 0原文

我有一个 PHP/MySQL 注册系统,它限制了可以注册某项内容的人数。假设有 5 个空位,其中 4 个已满。现在,登录的 2 个不同用户同时提交了一个表单,该表单执行 MySQL 查询以将该人添加到列表中。

简化后,PHP 逻辑看起来像这样:

if($numberOfSpotsTaken < 5) {
    //add user to list
}
else {
    //don't add user to list
}

现在,因为用户同时提交请求,所以当代码检查有多少名额被占用时,两个用户的名额都将低于 5。最终发生的情况是,两个请求都通过了,当限制应该为 5 时,最终有 6 个人出现在列表中。

如何防止这种情况,以便两个(或更多)用户在同一时间提交请求同一时间无法突破人数限制?

I have a PHP/MySQL sign-up system that limits the number of people who can sign up for something. So, let's say there are 5 spots available, and 4 of them are already full. Now, 2 different users who are logged in submit a form at the exact same time that executes a MySQL query to add that person to the list.

Simplified, the PHP logic looks something like:

if($numberOfSpotsTaken < 5) {
    //add user to list
}
else {
    //don't add user to list
}

Now, because the users both submit the request at the same time, when the code checks to see how many spots are taken, it will be under 5 for both. What ends up happening is that both requests go through and 6 people end up on the list when the limit is supposed to be 5.

How can I prevent this situation so that two (or more) users who submit a request at the same time can't bypass the limit of how many people can sign up?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

伤痕我心 2025-01-10 20:27:34

我通过使用 PDO 的 beginTransaction()rollBack()commit() 方法来防止超额预订,从而解决了这个问题。

简单地说,这就是我所做的:

<?php

$db->beginTransaction();

//add to list
$sth = $db->prepare("INSERT INTO...");
$sth->execute();

//select count from list
$sth = $db->prepare("SELECT ... FROM ...");
$sth->execute();

//check to see whether the list is overbooked -- in this case, 5 is the list limit
if($sth->rowCount() > 5) {
    $db->rollBack();
}
else {
    $db->commit();
}

?>

I was able to solve this problem by using PDO's beginTransaction(), rollBack(), and commit() methods to prevent overbooking.

Simplified, here's what I did:

<?php

$db->beginTransaction();

//add to list
$sth = $db->prepare("INSERT INTO...");
$sth->execute();

//select count from list
$sth = $db->prepare("SELECT ... FROM ...");
$sth->execute();

//check to see whether the list is overbooked -- in this case, 5 is the list limit
if($sth->rowCount() > 5) {
    $db->rollBack();
}
else {
    $db->commit();
}

?>
半窗疏影 2025-01-10 20:27:34

MySQL 只允许单个用户一次写入单个数据库。

我建议您检查页面加载和提交。如果您不检查服务器端的所有内容(用户提交的数据、可用性等),那么您的脚本就会非常不安全。

如果您真的认为有人可能会在几微秒内溜进来,请在“成功”后检查脚本以查看有多少条目。如果太多,请删除最新条目,直至正确的数量。

确保你这么想并处理任何错误:D

MySQL only allows a single user to write to a single database at a single time.

I would recommend that you check on page load AND on submission. If you are not checking everything (user submitted data, availability, etc) server-side, then you're going to make your scripts very insecure.

If you really really think somebody might slip in in a few microseconds, then have the script check after 'success' to see how many entries there are. If there are too many, remove the latest entries down to the correct number.

Make sure you think this though and handle any errors :D

泪眸﹌ 2025-01-10 20:27:34

我去找你的答案,发现了这个:

事务数据库锁定

I went looking for an answer for you and found this:

Transactional DB Locking

百思不得你姐 2025-01-10 20:27:34

从技术上讲,您的情况可能会发生,但这几乎是不可能的。 MySQL 确实允许多次插入,这就是获取独占锁的用武之地。请参阅此处的 MySQL 文档。 http://dev.mysql.com/doc/refman /5.0/en/innodb-locks-set.html

Technically your scenario can happen, but it's almost impossible. MySQL does allow multiple inserts which is where obtaining an exclusive lock comes in. See MySQL's documentation here. http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文