まず第一に、私はデータベース関連のことはまったく初めてであり、これから表示しようとしているクエリは、あなたの目にはひどいものに見えるかもしれないと言いたいです。:)しかし、私がいくつかの答えを求めているのは、クエリ自体ではありません。
私の問題は、マルチスレッド サーバー (Google App Engine (GAE) を使用) を使用していることです。つまり、データベースへの複数の接続を開き、まったく同じクエリをまったく同時に実行できます。「auto-commit = true」でクエリを実行すると、すべてが機能し、ロック待機タイムアウトなどはありません。しかし、「auto-commit = false」の場合、ロック待機タイムアウトが発生します。以下の例を参照してください。
connection.setAutoCommit(true);
String query = "INSERT INTO tblGameSession (gameID, createdBy, betAmount) VALUES ((SELECT gameID FROM(SELECT a.gameID, TIMESTAMPDIFF(HOUR, a.toc, NOW()) as timePassed FROM tblGameSession AS a LEFT JOIN tblGameSessionRoundData AS b ON a.gameID = b.gameID WHERE a.status = 1 AND b.language = ? AND b.category = ? AND a.betAmount = ? AND a.createdBy != ? HAVING timePassed < ? ORDER BY a.toc ASC LIMIT 1) as abc), ?, ?) ON DUPLICATE KEY UPDATE gameID=LAST_INSERT_ID(gameID), status = 0";
PreparedStatement stmt = connection.prepareStatement(query,Statement.RETURN_GENERATED_KEYS);
stmt.setInt(1, languageID);
stmt.setInt(2, categoryID);
stmt.setInt(3, betAmount);
stmt.setString(4, searchingPlayer);
stmt.setInt(5, GameSettings.getSetting(Settings.ExpireHours));
stmt.setString(6, searchingPlayer);
stmt.setInt(7, betAmount);
stmt.executeUpdate();
ResultSet generatedKeys = stmt.getGeneratedKeys();
generatedKeys.next();
long gameID = generatedKeys.getLong(1);
テーブルが InnoDB であるため、これはすぐに小さなトランザクションとして実行されます。ただし、以下の例は失敗し、「ロック待機タイムアウトを超えました。トランザクションを再起動してください」というメッセージが表示されます。
connection.setAutoCommit(false);
String query = "INSERT INTO tblGameSession (gameID, createdBy, betAmount) VALUES ((SELECT gameID FROM(SELECT a.gameID, TIMESTAMPDIFF(HOUR, a.toc, NOW()) as timePassed FROM tblGameSession AS a LEFT JOIN tblGameSessionRoundData AS b ON a.gameID = b.gameID WHERE a.status = 1 AND b.language = ? AND b.category = ? AND a.betAmount = ? AND a.createdBy != ? HAVING timePassed < ? ORDER BY a.toc ASC LIMIT 1) as abc), ?, ?) ON DUPLICATE KEY UPDATE gameID=LAST_INSERT_ID(gameID), status = 0";
PreparedStatement stmt = connection.prepareStatement(query,Statement.RETURN_GENERATED_KEYS);
stmt.setInt(1, languageID);
stmt.setInt(2, categoryID);
stmt.setInt(3, betAmount);
stmt.setString(4, searchingPlayer);
stmt.setInt(5, GameSettings.getSetting(Settings.ExpireHours));
stmt.setString(6, searchingPlayer);
stmt.setInt(7, betAmount);
stmt.executeUpdate();
ResultSet generatedKeys = stmt.getGeneratedKeys();
generatedKeys.next();
long gameID = generatedKeys.getLong(1);
connection.commit()
これはまったく同じことをするべきではありませんか?現在のシナリオでは、6 つのクライアントが同時にこれを実行しようとしています。最初のアプローチを使用するとうまくいきますが (実際には良すぎます)、2 番目のアプローチはひどく失敗します。そして、私はこの部分がより大きな取引の一部であることが本当に必要です。
アイデアはありますか?:)
(そして、これが何のためにあるのか疑問に思っている人のために:) クエリは、開始されたゲームの gameID を取得するために使用されます。ゲームが見つかった場合はステータス = 0 (取得済み) に更新され、ゲームが見つからない場合はステータス = 1 (無料) の新しいゲームが作成されます。作成 (または更新) された gameID は、そのゲームの追加データを取得するために使用されます。