繁体   English   中英

什么时候释放“ SELECT…FOR UPDATE”锁?

[英]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()时仅确保确实释放了锁定?

还有什么我想念的/做错了吗?

编辑:发生锁定时,所有已连接的客户端似乎都在响应,当前未进行任何查询,但是关闭所有已连接的客户端确实可以解决问题。 这使我认为,即使通过提交或回滚来结束事务(据说?)结束,锁仍以某种方式得以保留。

即使不关闭StatementResultSet是一个坏主意,但该函数似乎对您收到的错误不负责。 函数getNextIndex()正在创建本地StatementResultSet ,但未关闭它。 saveRecordInternal()将其关闭,或在saveRecordInternal()创建那些StatementResultSet对象,并将其作为参数传递,或者如果在起点处创建并一次又一次重复使用则更好。 最后,在不再需要时关闭它们(按以下顺序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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM