发布mysql锁外部事务(rails)

时间:2015-04-07 20:03:34

标签: mysql ruby-on-rails

我们最近看到很多错误:

ActiveRecord::TransactionIsolationConflict: Transaction isolation conflict detected: Lock wait timeout exceeded; try restarting transaction

无法弄清楚其背后的原因。但是在我们的代码中注意到一件事是试图锁定事务外的记录:

acc = Account.lock.find acc_id

上面的代码不在任何事务中,仅用于检查同样获得相同锁的其他事务是否已完成。如果这可能是罪魁祸首的任何想法?

2 个答案:

答案 0 :(得分:1)

当巨大的写入负载时,InnoDB使用行级锁定来获得更好的并发性。引擎采取一些预防措施来摆脱幻像读取,其中之一是gap_lock,这可能导致这个问题。使用

SHOW ENGINE INNODB STATUS

分析gap_lock。

如果这有问题,您可以尝试以下选项

  1. ISOLATION级别更改为READ COMMITTED

  2. set innodb_locks_unsafe_for_binlog = 1。除了外键约束检查或重复键检查外,这将禁用间隙锁。

  3. 再次使用show innodb status来分析正在发生的事情。如果需要,请优化代码以避免锁定

  4. 如果以上操作不起作用,请尝试全局增加lock_wait_timeout

  5. SET GLOBAL innodb_lock_wait_timeout = 120;

    或会议

    SET innodb_lock_wait_timeout = 120;
    
    1. 再次检查您的配置,如果仍未更新,则再次设置全局变量

      show variables like '%wait_timeout%';
      
      show variables like '%tx_isolation%';
      
      SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
      

答案 1 :(得分:0)

请检查MySQL服务器上为innodb_lock_wait_timeoutlock_wait_timeout配置的内容。 您可以通过运行以下命令来执行此操作

show global variables like '%lock_wait_timeout';

正在使用哪些参数取决于您的MySQL版本和表格的引擎

来自文档:

  

#select *来自帐户,其中id = 1表示更新

     

Account.lock.find(1)

for update表示 - 获取写入锁定。

您的交易可能需要比在数据库上配置的时间更长的时间,并且尝试验证原始交易的检查请求已完成 - 在等待的时间用完时收到此错误。