Java InnoDB,如果每次执行都是一个事务,那么为什么这不起作用?

Java InnoDB,如果每次执行都是一个事务,那么为什么这不起作用?,java,mysql,google-app-engine,transactions,innodb,Java,Mysql,Google App Engine,Transactions,Innodb,首先我想说的是,我对数据库的东西很陌生,我将要向你展示的查询在你眼里可能很可怕但我想要的答案不是问题本身 我的问题是,我有一个使用GoogleAppEngineGAE的多线程服务器,这意味着它可以打开到数据库的多个连接,并在完全相同的时间运行完全相同的查询。当在auto-commit=true中运行查询时,一切正常,没有锁等待超时等。但是当auto-commit=false时,我得到锁等待超时。见下例: connection.setAutoCommit(true); String query =

首先我想说的是,我对数据库的东西很陌生,我将要向你展示的查询在你眼里可能很可怕但我想要的答案不是问题本身

我的问题是,我有一个使用GoogleAppEngineGAE的多线程服务器,这意味着它可以打开到数据库的多个连接,并在完全相同的时间运行完全相同的查询。当在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个客户端试图同时执行此操作。使用第一种方法实际上效果太好,而第二种方法却失败得很厉害。我真的需要这部分成为更大交易的一部分

有什么想法吗

对于那些想知道这是为了什么的人:
查询用于获取已启动游戏的gameID。如果它发现一个游戏,它会更新它的状态=0,如果它没有发现任何游戏,它会创建一个状态=1的新游戏。创建或更新的gameID将用于检索该游戏的其他数据。

尝试将提交放在executeUpdate之后。。。请添加一些stacktrace。这也不行!我将用stacktrace更新我的帖子。为什么不把这个大而复杂的语句分解成小的语句,并将它们放在大事务中?@tarik:我一开始确实是这样做的。我将内部查询作为独立查询,使用FOR UPDATE来防止读取。但这也导致了一个锁,然后它锁定了两个表,而不是一个表。我真的需要连接这两个表:/这个问题可能只发生在本地testserver上。我使用的是谷歌应用引擎GAE,据我所知,我在live服务器上没有锁定超时。不确定是什么原因导致了这种情况,因为锁放在远程数据库中,而不是服务器本身。因此,本地服务器上的提交可能从未真正提交,因此会锁定数据库。关于这一点,还有更多的答案!非常感谢。