ActiveRecord::StatementInvalid: Mysql2::Error: Lock wait timeout exceeded 活动记录::语句无效: Mysql2::错误: 锁等待超时
ActiveRecord::StatementInvalid: Mysql2::Error: Lock wait timeout exceeded 活动记录::语句无效: Mysql2::错误: 锁等待超时
在我的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
sidekiq.yml
# 这里的选项仍然可以被命令行参数覆盖。
# 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
当数据库大小增长并且显式执行了大量事务时,就会出现这个问题,可能是其他线程在某个记录上持有记录锁的时间过长,导致你的线程超时。
我使用的一个解决方法是延长等待超时时间。
通过终端登录到MySQL并运行以下命令:
SET GLOBAL innodb_lock_wait_timeout = 28800;
另一件你可以做的事情是在MySQL中强制解锁被锁定的表:
像这样打破锁定常常会导致数据库中的原子性在引起锁定的SQL语句上不被执行。
这是一种hack方法。正确的解决方法是修复导致锁定的应用程序。
在使用ActiveRecord时,有时候会遇到一个错误信息:ActiveRecord::StatementInvalid: Mysql2::Error: Lock wait timeout exceeded。那么这个问题是如何出现的呢?又该如何解决呢?
这个错误信息的意思是正在操作的记录被另一个较慢的SQL锁定,并且已经等待很长时间了。这通常是由于代码中存在较长的事务导致的。为了解决这个问题,我们可以进行以下几步操作:
1. 检查代码,找出慢SQL语句。可以使用数据库查询日志或者性能分析工具来定位具体的慢SQL语句。
2. 优化慢SQL语句。可以通过添加索引、优化查询语句等方式来提高SQL语句的执行效率。
3. 拆分长事务。将长事务拆分成多个较短的事务,可以减少事务锁定的时间,从而避免出现锁等待超时的问题。
希望这些方法对你有所帮助。如果你遇到了ActiveRecord::StatementInvalid: Mysql2::Error: Lock wait timeout exceeded这个错误,可以尝试以上解决方法来解决问题。
这个错误是由于在不同的工作器尝试修改相同资源时的事务超时而发生的,基本上是一个数据库死锁。它发生在以下情况下:如果您明确使用事务,如SomeModel.transaction { SomeModel.task_that_takes_too_much_time }
,或者使用修改记录的普通ActiveRecord方法,因为所有操作都包装在事务中。
唯一的建议是探索使您的工作器成为唯一的替代方案,例如使用https://github.com/mhenrixon/sidekiq-unique-jobs并使您的作业使用.perform_in
方法。