0

首先,我想说我对数据库的东西很陌生,我即将向您展示的查询在您看来可能看起来很糟糕。:) 但我想要一些答案的不是查询本身。

我的问题是我有一个多线程服务器(使用 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 个客户端同时尝试执行此操作。使用第一种方法有效(实际上太好了),而第二种方法则失败了。我真的需要这部分成为更大交易的一部分。

那么有什么想法吗?:)

(对于那些想知道这是干什么用的人:)该查询用于获取已经开始的游戏的游戏 ID。如果它找到了一个游戏,它会更新它的状态 = 0(采取),如果它没有找到任何游戏,它将创建一个状态 = 1(免费)的新游戏。创建(或更新)的游戏 ID 然后将用于检索该游戏的其他数据。

4

0 回答 0