在我的应用程序中,我遇到一个问题,有时SELECT语句会遇到java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
异常。遗憾的是,由于情况非常复杂,我无法创建示例。因此,问题只是关于一般的了解。
一些背景信息:我正在使用具有READ_COMMITED隔离级别的MySQL(InnoDB)。
实际上,我不了解SELECT如何通过该设置遇到锁定超时。我以为SELECT永远不会锁定,因为它只会返回最新的提交状态(由MySQL管理)。无论如何,根据发生的事情,这似乎是错误的。那真的怎么样?
我已经读过https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html,但这并没有给我任何线索。不使用SELECT ... FOR UPDATE
或类似的东西。
答案 0 :(得分:1)
那可能是由于您的数据库。通常,这类问题来自那一侧,而不是来自访问它的编程一侧。以我对db的经验来看,这些问题通常是由于这一点造成的。最后,编程方面只是“在数据库中为我自己准备”。
我发现this并不费力。
它的基本解释是:
Lock wait timeout
通常发生在某个事务正在等待要更新的数据行(该数据已被某个其他事务锁定)时。
您还应该检查this answer中存在特定事务问题,这可能会对您有所帮助,因为尝试更改不同的表可能会导致超时
查询试图更改一个或多个InnoDB表中的至少一行。既然您知道查询,那么所有被访问的表都是罪魁祸首。
答案 1 :(得分:1)
要加快数据库中的查询速度,可以同时执行多个事务。例如,如果某人在一个表上运行一个查询,查询某公司员工的工资(每位员工用一个ID标识),而另一个人更改了某人的姓氏,例如结婚后,您可以同时执行两个查询,因为它们不会相互干扰。
但是在其他情况下,即使SELECT语句也可能会干扰另一个语句。
为防止SQL事务中出现意外结果,事务遵循 ACID模型,该模型代表原子性,一致性,隔离性和持久性(有关更多信息,请阅读wikipedia)。
比方说,事务1开始计算某些东西,然后想要将结果写入表A。在写入事务1之前,它将所有SELECT语句锁定到表A。否则,这会干扰隔离要求。因为如果事务2在1仍在写入时开始,那么2的结果取决于1已写入的位置和未写入的位置。
现在,它甚至可能产生死锁。例如。在事务1可以将数据写入表A的最后一个字段之前,它仍然必须向表B写入内容,但是事务2已经阻止了表B以便从表B中安全地对其进行读取,现在您已经陷入了死锁。 2想要从被1阻塞的A中读取数据,因此它等待1完成,但是1等待2解锁表B本身完成。
要解决此问题,一种策略是在特定超时后回滚特定事务。 (more here)
因此,这可能是您的select语句的继续阅读,以超出锁定等待超时的时间。
但是僵局通常是偶然发生的,因此,如果事务2被迫回滚,事务1应该能够完成,以便事务2在以后的尝试中能够成功。