ActiveRecord“Mysql :: Error:超出锁定等待超时”,没有明显的锁定

时间:2011-01-24 21:14:37

标签: mysql ruby-on-rails activerecord locking timeout

Rails版本:2.3.8

很多时候,我的应用程序似乎会随机返回500错误,并在生产日志中输入相应的条目:

ActiveRecord::StatementInvalid (Mysql::Error: Lock wait timeout exceeded; try restarting transaction: INSERT INTO `forum_posts` (`forum_topic_id`, `created_at`, `body`, `ancestry`, `updated_at`, `quote_limit`, `user_id`, `ancestry_depth`, `quote_root`) VALUES(1224783, '2011-01-24 19:18:38', 'Post body', '1285704', '2011-01-24 19:18:38', 1, 57931, 1, 1))

检查MySQL慢查询日志会将此条目显示为:

# Time: 110124 11:19:29
# User@Host: db_user[db_user] @ localhost []
# Query_time: 51  Lock_time: 0  Rows_sent: 0  Rows_examined: 0
SET insert_id=0;
INSERT INTO `forum_posts` (`forum_topic_id`, `created_at`, `body`, `ancestry`, `updated_at`, `quote_limit`, `user_id`, `ancestry_depth`, `quote_root`) VALUES(1224783, '2011-01-24 19:18:38', 'Post body', '1285704', '2011-01-24 19:18:38', 1, 57931, 1, 1);

根据Rails日志,由于锁定等待超时,ActiveRecord返回错误。这个简单查询的长期运行性质似乎也是如此。问题是,我找不到一个需要很长时间才能处理的实际查询的慢查询日志 - 它们都与上面的例子类似。另外,在同一个日志中,没有一个条目的Lock_time值大于0.

这里有没有人知道可能导致这种明显锁定的原因以及如何隔离它?我正在使用的当前工具似乎没有多大帮助。

提前致谢。

1 个答案:

答案 0 :(得分:4)

也许这会有所帮助: http://www.mysqlperformanceblog.com/2007/02/25/pitfalls-of-converting-to-innodb/

我们经常建议客户将他们当前的数据库从MyISAM表转换为InnoDB。 在大多数情况下,传输本身几乎都很简单,但应用程序可以通过新的意外错误来解决 1205(ER_LOCK_WAIT_TIMEOUT) 锁定等待超时已到期。交易被回滚。 1213(ER_LOCK_DEADLOCK) 交易死锁。您应该重新运行该交易。

处理这些错误并不难,但你应该知道。 这是我们在PHP应用程序中做的一些事情:

class mysqlx extends mysqli {

...

  function deadlock_query($query) {
          $MAX_ATTEMPS = 100;
          $current = 0;
          while ($current++ < $MAX_ATTEMPS) {

                  $res = $this->query($query);

                  if(!$res && ( $this->errno== '1205' || $this->errno == '1213'  ) )
                                  continue;
                  else 
                          break;
             }
 } 
...
}

您可能希望以不同的方式处理ER_LOCK_WAIT_TIMEOUT,尤其是对于长时间等待不好的Web应用程序,您会明白这一点。