2

次の列のテーブルがあります:[user_id] [game_id] 2人のプレーヤーがゲームに参加したら、ゲームを閉じる必要があります。私はこのコードを使用しました:

if(mysql_num_rows(mysql_query("SELECT user_id FROM live_games WHERE game_id = '$gid'"))<2){
mysql_query("INSERT INTO live_games (user_id, game_id) VALUES ('$uid', '$gid')");
echo "You have joined the game";
}else{
echo "Table is full";
}

コードでは2人のプレーヤーしか登録できませんが、Webサイトにユーザーが多すぎる場合、この条件は機能せず、3人のユーザーがテーブルに追加されます。どうすれば修正できますか?

4

3 に答える 3

4

いくつかのオプションがあります。

  1. InnoDBストレージエンジンを使用している場合は、ステートメントSELECT ... FOR UPDATEと同じトランザクション内でロッキング読み取りを実行します。INSERT

    PDOの使用:

    $dbh = new PDO("mysql:dbname=$dbname;charset=utf8", $username, $password);
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    
    $dbh->beginTransaction();
    $qry = $dbh->prepare('
      SELECT COUNT(*) FOR UPDATE FROM live_games WHERE game_id = ?
    ');
    $qry->execute([$gid]);
    
    if ($qry->fetchColumn() < 2) {
      $qry = $dbh->prepare('
        INSERT INTO live_games (user_id, game_id) VALUES (?, ?)
      ');
      $qry->execute([$uid, $gid]);
      if ($qry->rowCount() && $dbh->commit()) echo 'You have joined the game';
    } else {
      $dbh->rollBack();
      echo 'Table is full';
    }
    
  2. 2つの列が存在するようにテーブル構造を変更し、player1player2最初はNULL)実行UPDATE live_games SET player2 = ? WHERE game_id = ? AND player2 IS NULLしてから、影響を受ける行の数を確認します。また

  3. 追加の列があるようにテーブル構造を変更してから、の上playerNumberに複合UNQUEインデックスを作成し(game_id, playerNumber)ます。

于 2012-09-16T15:15:00.993 に答える
0

誰かがゲームに参加できるかどうかを確認するために2つのクエリを実行しています。

3人のプレーヤーが同時にクリックして参加している可能性があり、SELECTクエリは、ゲームに(現在)0人のプレーヤーがいることを返します。したがって、それらはすべて許可されます-UPDATEはその後キックし、他のプレイヤーが参加するのを阻止します。

それを修正したい場合は、別の方法を見つける必要があります-ファイルロックを追加して、一度に1つのSELECTクエリのみが実行されるようにするか、トランザクションでラップすることも機能すると思います-これは基本的に、両方のクエリを単一のエンティティとして実行します。

于 2012-09-16T15:11:14.820 に答える
0

次のように、クエリをLOCKTABLESステートメントで囲む必要があります。

mysql_query("LOCK TABLES live_games WRITE");

if(mysql_num_rows(mysql_query("SELECT user_id FROM live_games WHERE game_id = '$gid'"))<2){
mysql_query("INSERT INTO live_games (user_id, game_id) VALUES ('$uid', '$gid')");
echo "You have joined the game";
}else{
echo "Table is full";
}

mysql_query("UNLOCK TABLES");

これにより、テーブルへのシリアルアクセスが強制されるため、異なるユーザーが同じコードを同時に実行することによる同時実行の問題を回避できます。

于 2012-09-16T15:14:35.910 に答える