【问题标题】:General error: 1205 Lock wait timeout exceeded; try restarting transaction一般错误:1205 超过锁定等待超时;尝试重启事务
【发布时间】:2021-01-12 17:54:46
【问题描述】:

我正在使用 Laravel + MySQL 开发一个用于在线考试评估的应用程序。许多用户同时提交他们的响应(在几分钟内),因此数据库服务器的负载很重。

在许多并发提交期间,我收到了几个 General error: 1205 Lock wait timeout exceeded; try restarting transaction

我启用了慢查询日志并在我的日志中看到了以下条目

update `form_responses` set `photo_url` = 'https://example.com/ae252b371effc7cb11dbcbbb18602026.jpg', `form_responses`.`updated_at` = '2020-09-26 11:39:17' where `id` = 32407;

根据我的理解,这只是一个简单的行更新,其中查询了一个主列(意味着索引应该可以工作)。

但我无法理解的是 - 为什么 Innodb 不使用行级锁定并在此特定行上提供锁定。是否有一些特定的 Innodb 值我应该增加它以防万一?

【问题讨论】:

  • 请考虑将慢查询日志的最后 100 行发布到 pastebin.com(并分享 url)并完成 SHOW ENGINE INNODB STATUS 的 TEXT 结果;在这些事件之一之后进行分析。
  • @VikasSinghai 请考虑在 9 月 26 日 17:54 发布要求的信息,并发布 SHOW CREATE TABLE form_responses 的 TEXT 结果;进行分析。谢谢

标签: mysql laravel


【解决方案1】:

InnoDB 使用行级锁定。

问题是,应用程序或 ORM 以错误的方式使用它,没有为 MySQL 提供足够的信息来说明要做什么,从而导致死锁。

最简单的 - 我赶紧说,不是最有效的! - 如果您发现更新都发生在同一小组方法中,则解决此问题的方法可能是诉诸建议锁定

请注意,您的死锁在该表中是完全不给定的;您应该运行 SHOW ENGINE INNODB STATUS 以查看最后检测到的死锁是什么。例如,您会发现:

LATEST DETECTED DEADLOCK
------------------------
200915 11:31:03
*** (1) TRANSACTION:
TRANSACTION 22B8A76B9, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 4 lock struct(s), heap size 1248, 4 row lock(s)
MySQL thread id 11161737, OS thread handle 0x7fd06d708700, query id ... UPDATE table SET ... WHERE Dat_UsrId = '11254' && Dat_CreUte='...' && Dat_Tip = 'C'

*** (2) TRANSACTION:
TRANSACTION 22B8A76B4, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
2616 lock struct(s), heap size 244152, 7262 row lock(s)
MySQL thread id 11161676, OS thread handle 0x7fd06ca97700, query id ... UPDATE table SET ... WHERE ...

*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 866959 page no 46 n bits 1616 index `NewIndex2` of table `schema`.`table` trx id 22B8A76B4 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;


*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 866959 page no 68831 n bits 72 index `PRIMARY` of table `schema`.`table` trx id 22B8A76B4 lock_mode X locks rec but not gap waiting
Record lock, heap no 5 PHYSICAL RECORD: n_fields 18; compact format; info bits 0

*** WE ROLL BACK TRANSACTION (1)
------------

请注意,这里的逻辑错误出现在事务 2 的查询中。这是一个非常强烈的提示:

2616 lock struct(s), heap size 244152, 7262 row lock(s)

...WHERE 需要锁定 7262 行 (!),从应用程序逻辑的角度来看,这完全是荒谬的(另请参阅 this 了解“间隙”的解释)。

否则,您可以借助LOCK TABLE form_responses WRITE 使用显式事务和表级锁定。

最有效的方法是让所有涉及的方法进入显式事务:

SET autocommit = 0;
UPDATE form_responses ... WHERE id = ...;
COMMIT WORK;

【讨论】:

    猜你喜欢
    • 2018-04-17
    • 2019-06-02
    • 2015-09-27
    • 2013-02-05
    • 2016-08-01
    • 1970-01-01
    • 2018-01-12
    • 2021-08-07
    • 1970-01-01
    相关资源
    最近更新 更多