ActiveRecord::StatementInvalid: Mysql2::Error: Lock wait timeout exceeded 活动记录:语句无效 - Mysql2错误:锁等待超时

4
在我的rails项目中,我使用sidekiq处理耗时任务,但在sidekiq日志中出现了错误:
ActiveRecord::StatementInvalid: Mysql2::Error: Lock wait timeout exceeded; try restarting transaction: UPDATE `marker_layers` SET `show_fields` = 'title,desc', `sort_col` = 'title,desc', `updated_at` = '2016-05-17 07:36:02' WHERE `marker_layers`.`id` = 16021210
Processor: iZ23edse84Z:29310

enter image description here sidekiq.yml

# Options here can still be overridden by cmd line args.
#   setsid sidekiq -d -C config/sidekiq.yml -e production
---
:concurrency: 5
:pidfile: tmp/pids/sidekiq.pid
:logfile: log/sidekiq.log
staging:
  :concurrency: 10
production:
  :concurrency: 40
:queues:
  - ['critical', 3]
  - ['default', 2]
  - ['low', 1]

database.yml

production:
   adapter: mysql2
   encoding: utf8mb4
   collation: utf8mb4_bin
   reconnect: false
   database: database_name
   pool: 48
   username: password
   password: password
   host: locahost

2
很可能有多个工作线程试图更新同一数据库行,而有些线程在等待访问时超时了。根据您提供的信息,我们无法得出更多结论。您应该重新检查代码中是否存在竞态条件,并查看死锁的来源... - averell
1
你可能会发现https://dev59.com/1m025IYBdhLWcg3wclm-有帮助。 - Frederick Cheung
您可能还想了解innodb_lock_wait_timeoutinnodb_deadlock_detect变量。 - Jared Beck
3个回答

0

这个错误是由于事务超时而发生的,当不同的工作进程试图修改相同的资源时,基本上就会出现数据库死锁。

如果您明确使用事务,例如 SomeModel.transaction { SomeModel.task_that_takes_too_much_time } 或者使用普通的 ActiveRecord 方法来修改记录,因为所有内容都包装在一个事务中,所以也会发生这种情况。

我唯一能给您的建议是探索替代方案,使您的工作进程变得独特,例如使用 https://github.com/mhenrixon/sidekiq-unique-jobs 并使您的工作使用 .perform_in


0

这意味着操作记录已被另一个缓慢的SQL锁定,并且已经等待了很长时间。

也许你的代码中有许多长时间的事务。

检查你的代码,优化缓慢的SQL并分割长时间的事务。

我希望这对您有所帮助。


0

这种情况通常发生在数据库大小增长并且您明确地执行了大量事务时,可能有其他线程长时间持有某个记录的记录锁,导致您的线程超时。

我使用的一个解决方案是延长等待超时时间。

通过终端登录到MySQL并运行以下命令:

SET GLOBAL innodb_lock_wait_timeout = 28800;

你可以做的另一件事是在MySQL中为锁定的表强制解锁:

像这样打破锁定通常会导致数据库上的原子性未被执行,对于导致锁定的SQL语句也是如此。

这是一个hack。正确的解决方案是修复导致锁定的应用程序。

MySQL中锁定表的强制解锁:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接