[英]When is `SELECT … FOR UPDATE` lock released?
我正在开发一个程序,该程序允许多个用户访问数据库(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()
时仅确保确实释放了锁定?
还有什么我想念的/做错了吗?
编辑:发生锁定时,所有已连接的客户端似乎都在响应,当前未进行任何查询,但是关闭所有已连接的客户端确实可以解决问题。 这使我认为,即使通过提交或回滚来结束事务(据说?)结束,锁仍以某种方式得以保留。
即使不关闭Statement
或ResultSet
是一个坏主意,但该函数似乎对您收到的错误不负责。 函数getNextIndex()
正在创建本地Statement
和ResultSet
,但未关闭它。 在saveRecordInternal()
将其关闭,或在saveRecordInternal()
创建那些Statement
和ResultSet
对象,并将其作为参数传递,或者如果在起点处创建并一次又一次重复使用则更好。 最后,在不再需要时关闭它们(按以下顺序ResultSet, Statement, Connection
)。
错误仅表示某个数据库对象(连接,表,行等)上存在锁,而另一个线程/进程同时需要该锁,但必须等待(已锁定),但由于等待时间长于预期,所以超时。
请参阅“ 如何避免锁定等待超时超出异常”。 了解有关此问题的更多信息。
总而言之,这是与环境有关的问题,需要在您的计算机上调试并启用大量日志记录。
希望能帮助到你 !!
从上面的语句中,我看不到任何锁保持打开状态! 通常,每当调用commit或rollback或关闭连接时,MySql都应释放锁。
就你而言
SELECT max(IDX) FROM MyTable FOR UPDATE
会锁定整个表,但是我认为这是预期的逻辑! 您锁定表,直到插入新行,然后释放它以让其他人插入。 我会测试:
SELECT IDX FROM MyTable FOR UPDATE Order by IDX Desc LIMIT 1
确保即使锁定单行时锁也保持打开状态。
如果不是这种情况,由于表很大,我可能是锁定超时。
因此,我认为这里发生的事情是:您的查询试图在某个表上执行,但是该表被另一个进程锁定。 因此,直到较旧的锁不会从表中释放之前,您的查询将等待执行,如果过了一段时间,如果锁没有释放,您将收到锁超时异常。
您还可以查看表级锁和行级锁。 简而言之:表级锁会锁定整个表,直到该锁存在为止,您都希望能够在同一表上执行任何其他查询。 行级锁定将锁定特定的行,因此除了该行之外,您还可以在表上执行查询。
您还可以检查表中是否有长时间运行的查询,并且由于该原因您无法执行其他查询并获得异常。 如何检查此方法将因数据库而异,但是您可以针对特定数据库在Google上进行查询,以查找查询以获取对数据库的开放连接或长期运行的查询。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.