私はajaxを介してphpとjqueryで動作するゲームを開発しました。
基本的に、サーバーにリクエストが行われると、まだ開いているゲームがない場合、サーバーは新しいゲームを作成します。ゲームのデータベーステーブルは次のようになります。
id | closed | time
ゲームが終了すると、closedは1に設定され、timeはゲームが作成されたときのUNIXタイムスタンプです。
ここで重要なことは、テーブルには常にclosed = 0のゲームが1つしか存在できないということです。
これを行うために、私は次のphpコードを使用しています
$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;
}
たまに2つのゲームが作成されることもあります。2つのゲームが開いているときは時間の値が常にまったく同じであるため、2つのリクエストがまったく同時に送信されるためだと思います。
テーブルにclosed = 0のゲームが2つ存在しないことを、100%確実にできる方法はありますか?
あなたが2つのレコードで終わる可能性のある理由は、あなたが疑うように、並行性です。2つのプロセスがSELECT
最初に別々にクエリを実行する場合、両方が青信号を取得して続行し、両方がを実行しINSERT
ます。したがって、そのような行は2つ(またはそれ以上!)になります。
従来は、これを回避するためにトランザクションまたはロックを使用していましたが、単一のアトミッククエリでこれを実行できるSQLの「トリック」もあります。
INSERT INTO game_roulette SELECT NULL、x.closed、NOW() FROM (SELECT '0' as close )x LEFT JOIN game_roulette g ON x.closed = g.closed WHERE g.id IS NULL
それはです:ちょうどこれがどのように動作するかを説明するためINSERT ... SELECT
の構文、SELECT
何行がない場合、クエリは結果だけを得game_roulette.closed
ているが'0'
。次に、これは、単一の行テーブルを作成しx
、次にon列LEFT JOIN
に対して実行し、制約を使用することによって実行されます。game_roulette
closed
g.id IS NULL
このクエリの完了後、必要に応じて、アプリケーションは、他の場合と同様に、の結果をチェックして、結果INSERT
として行が挿入されたかどうかを知ることができます。
注:大きなテーブルでこれを行う場合は、クエリのパフォーマンスを測定するか、closed
列にインデックスがあり、それが使用されていることを確認する必要があります。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加