为什么 SELECT 会等待锁定?

在我的应用程序中,我遇到了有时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


撒科打诨
浏览 319回答 2
2回答

慕妹3146593

这可能是由于您的数据库。通常,这种问题来自该侧,而不是来自访问它的编程端。根据我对db的经验,这些问题通常是由于这一点。最后,编程方面只是“在那个数据库里为我得到那个”的事情。我毫不费力地找到了这个。它基本上解释了:Lock wait timeout通常发生在事务正在等待数据行更新时,该数据行已被其他事务锁定。您还应该检查这个具有特定事务问题的答案,这可能会对您有所帮助,因为尝试更改不同的表可能会超时查询试图更改一个或多个InnoDB表中的至少一行。由于您知道查询,因此所有被访问的表都是罪魁祸首的候选项。

一只名叫tom的猫

为了加快数据库中的查询速度,可以同时执行多个事务。例如,如果有人对公司员工的工资表运行选择查询(每个员工由id标识),而另一个更改了例如已婚人士的姓氏,则可以同时执行这两个查询,因为它们不会干扰。但在其他情况下,即使是 SELECT 语句也可能会干扰另一个语句。为了防止SQL事务中的意外结果,事务遵循ACID模型,该模型代表原子性,一致性,隔离性和持久性(有关更多信息,请阅读维基百科)。假设事务 1 开始计算某些内容,然后想要将结果写入表 A。在编写之前,它会将所有 SELECT 语句锁定到表 A。否则,这会干扰隔离要求。因为如果事务 2 在 1 仍在写入时启动,则 2 的结果取决于 1 已写入的位置和未写入的位置。现在,它甚至可能产生死锁。例如,在事务 1 可以写入表 A 中的最后一个字段之前,它仍然必须向表 B 写入一些内容,但事务 2 已经阻止了表 B 在从 A 读取后安全地读取表 B,现在你有一个死锁。2 想要从被 1 阻止的 A 读取,因此它等待 1 完成,但 1 等待 2 解锁表 B 自行完成。为了解决这个问题,一种策略是在某个超时后回滚某些事务。(更多这里)因此,这可能是您的 select 语句的读取,以获得超过锁定等待超时。但是死锁通常只是巧合发生的,所以如果事务 2 被迫回滚,事务 1 应该能够完成,以便 2 应该能够在以后的尝试中成功。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java