【发布时间】:2016-03-30 15:55:44
【问题描述】:
我正在开发一个允许多个用户访问数据库(MySQL)的程序,并且在不同的时间我得到一个 SQLException: Lock wait timeout exceeded 。
使用以下方式创建连接:
conn = DriverManager.getConnection(connString, username, password);
conn.setAutoCommit(false);
所有调用都通过这段代码:
try {
saveRecordInternal(record);
conn.commit();
} catch (Exception ex) {
conn.rollback();
throw ex;
}
saveRecordInternal 有一些内部逻辑,保存给定的记录。一路上的某个地方是我怀疑是问题的方法:
private long getNextIndex() throws Exception {
String query = "SELECT max(IDX) FROM MyTable FOR UPDATE";
PreparedStatement stmt = conn.prepareStatement(query);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
return (rs.getLong("IDX") + 1);
} else {
return 1;
}
}
如果需要,此方法由saveRecordInternal 在其操作过程中的某处调用。
由于目前我无法控制的原因,我不能使用自动增量索引,而且无论如何,某些内部程序逻辑需要插入的索引。
我认为调用conn.commit() 或conn.rollback() 就足以释放锁,但显然不是。所以我的问题是——我应该在getNextIndex 中使用stmt.close() 还是rs.close()?是在事务提交或回滚之前释放锁,还是只是确保在调用conn.commit() 或conn.rollback() 时确实释放了锁?
我还有什么遗漏/完全错误的吗?
编辑:在锁定发生时,所有连接的客户端似乎都有响应,目前没有查询正在进行,但关闭所有连接的客户端确实可以解决问题。这让我认为,即使事务(假设?)通过提交或回滚结束,锁也会以某种方式被保留。
【问题讨论】: