0

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

服务器使用 PHP 5.2.0,这说明我不使用 DateTime 类。我的表winnertable 是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 表只锁定了标记为更新的选定行。我不知道从那里做什么。
  • 使我的“日期”列唯一应该防止多次插入同一日期,这似乎是一个优雅的解决方法,但它似乎有点太容易被信任,我真的很想得到你的建议。
4

2 回答 2

0

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

于 2013-09-26T17:48:24.197 回答
0

我终于决定以不同的方式思考这个问题,并决定发布解决方案,因为它可能会对某些人有所帮助。

我已阅读 InnoDB 表行级锁定并执行了以下操作:

stmt #1:更新获胜者表 SET id_main=[id] WHERE date_add(next_date, INTERVAL X SECOND) < NOW() AND id_main = 0

如果 PDO 返回修改后的行 ($stmt->rowCount()) 那么它就是获胜者,您必须在获胜者表中为下一个获胜者插入新行:

Stmt #2(有条件的):INSERT INTO Winnertable SET next_date=NOW()

感谢您的帮助!

于 2013-10-10T12:56:39.197 回答