duanpin9531 2016-04-04 03:28
浏览 35
已采纳

在mysql中一次只能允许1个开放条目

I have developed a game which works with php and jquery through ajax.

Essentially, when a request is made to the server the server will create a new game if there is not already one open. My database table for the games looks as follows:

id | closed | time

Where closed will be set to 1 once a game is over, and time is the unix timestamp of when the game was created.

Now the important thing here is that at any given time there can only be 1 game with closed = 0 in the table.

To do this I am using the following php code

$query = "SELECT id FROM games WHERE closed = '0' LIMIT 1";
$result = $this->database->query($query);
if ($result->num_rows == 0) {
    $query = "INSERT INTO games_roulette SET time = '".time()."'";
    $result = $this->database->query($query);
    return $this->database->insert_id;
} else {
    return false;
}

The thing is occasionally 2 games will be created, I believe due to 2 requests being sent at the exact same time, as the time values are always the exact same when there are 2 games open.

Is there any way I can have 100% certainty that there will never be 2 games with closed = 0 in the table?

  • 写回答

1条回答 默认 最新

  • douzhaocheng4533 2016-04-04 05:57
    关注

    The likely reason you end up with 2 records is, as you suspect, concurrency. If 2 processes separately run the SELECT query first, they'll both get the green light to proceed, and they'll both run the INSERT. So you end up with 2 (or more!) such rows.

    Traditionally, you'd use transactions or locks to avoid this, but there's also an SQL "trick" that would allow a single atomic query to accomplish this:

    INSERT INTO
      game_roulette
    SELECT NULL, x.closed, NOW()
      FROM
        (SELECT '0' as closed) x
        LEFT JOIN game_roulette g ON x.closed = g.closed
      WHERE
        g.id IS NULL
    

    Just to explain how this works: it's an INSERT ... SELECT syntax, where the SELECT query only yields a result if there's no row where game_roulette.closed is '0'. This, in turn, is done by creating a single row table x, then doing a LEFT JOIN against game_roulette on closed column and using the g.id IS NULL constraint.

    After the completion of this query, if needed, the application can check the result of the INSERT, just as it would do for any other, to know if any row(s) were inserted as a result.

    Note: if you're doing this on a large table, you should measure the query performance and/or make sure there's an index on closed column and it's getting used.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类