php - 防止 MySQL 和 InnoDB 并发访问和插入

标签 php mysql innodb

我目前正在制作一个立即获胜的游戏,规则如下:第一个在最后一个注册后至少半小时注册的用户获胜。所以用户每半小时就可以中奖一次。如果几个小时内没有人注册,则第一个注册的人获胜。

服务器使用 PHP 5.2.0,这说明我不使用 DateTime 类。我的获胜表是 InnoDB。

我的脚本的这一部分在用户注册时由每个客户端调用,并决定用户是否获胜:

$currentTime = date("Y-m-d H:i:s");

// We're looking for the last winner in the winners table
$res = $dbh->query("SELECT date FROM winnertable ORDER BY id DESC")->fetch(PDO::FETCH_ASSOC);

if(empty($res)){
    // If there is no last winner then the user wins
    $winner = true;
}else{
    // If there is already a last winner, we check the date of win, if superior to half an hour, the user wins 
    if(strtotime($currentTime)-strtotime($res["date"])>=1800){
        // Last winner was half an hour ago : winner
        $winner = true;
    }
}

// if the winner flag is set to true, add the user id to the winners table along with the date of winning
if($winner){
    $dbh->query("INSERT INTO winnertable (id_main, date) VALUES ('".$_SESSION['id']."', '".$currentTime."')");
}

下一页必须向用户显示结果,以便他知道自己是否获胜。所以我不能让 CRON 工作事后决定。

这个脚本是有缺陷的,因为如果多个客户端同时访问,它可能会让多个客户端获胜。

我读过一些解决方案:

  • 使用锁:但我不知道性能成本。另外,我读到 MyIsam 表锁定了整个表,而 InnoDB 表只锁定了标记为更新的选定行。我不知道接下来该做什么。
  • 使我的“日期”列唯一应该可以防止多次插入同一日期,这似乎是一个优雅的解决方法,但似乎有点太容易被信任,我真的很想听听您的建议。

最佳答案

您可以做的是在这种情况下添加一个进一步的阶段,从而您有另一个临时表来存储“潜在”获胜者 - 满足获胜标准的获胜者。然后对其运行 SELECT 作为辅助操作,按日期排序,索引按升序排列,限制为 1。将该值添加到真正的获胜者表中,并将其作为下一次获胜计算的基础,并清除临时表。这样你就只能得到一个获胜者。当然,这会增加开销,但它只会每半小时发生一次,所以我认为这不应该是一个太大的问题。

关于php - 防止 MySQL 和 InnoDB 并发访问和插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19034088/

相关文章:

php - 将 curl 与 php 一起使用无法连接对等重置

mysql - 带前滚日志的增量备份 : How to get the logs with MySQL commands?

python - Python 中的 MySQL 动态查询语句

MySQL 一张表与多张表的性能对比

php - .htaccess 与产品(字符串)

php - MySQL连接 'asking for reconnection'

mysql - MySQL 的 dict_col_struct 中的 ord_part 是什么?

mysql - 估计 MySQL "SELECT WHERE EXISTS"查询的结果数?

php - 如何在 mongodb 中提取对象 ID 并对其进行搜索?

php - PHP中的分页