2012-03-13 76 views
0

我有一个自定义session.set_save_handler来处理我的应用程序的基于数据库的会话。数据库表是innodb类型。我在我的日志文件类型(1205) Lock wait timeout exceeded; try restarting transaction中看到一些错误,这些错误包含多个线程,这会挂起应用程序。如何使用set save handler在基于PHP数据库的会话中处理“锁定等待超时”错误?

另外,我有一个包含会话处理器回调的一类,并使其成为单例类:

session_set_save_handler(
     array($this, "db_open"), 
     array($this, "db_close"), 
     array($this, "db_read"), 
     array($this, "db_write"), 
     array($this, "db_destroy"), 
     array($this, "db_gc") 
     ); 

在“db_open”的方法,我设置自动提交为false。

在“db_read”的方法,我与会话ID的行做一个SELECT FOR UPDATE。所以,当我的应用程序执行负载测试。其中有很多ajax调用db更新,我注意到lock wait timeout错误。

在“db_write”的方法,我做一个明确的“提交”或“回滚”。

我该如何解决这个问题呢?有什么建议么?

  1. 我应该抓住这些错误,并发出在 读一个明确的“提交”或编写方法来释放锁,然后重试?
  2. 我应该为“innodb_lock_wait_timeout”

感谢

回答

0

你因为一些交易的未发行的锁没有完成某种原因,指定一个较高的超时值 。 InnoDB的锁等待超时变量的

设置更大的价值:innodb_lock_wait_timeout=300

然后,重新启动MySQL服务器。

如果没有帮助,也许你的表已损坏,然后请参阅这篇文章:Recovering Innodb table Corruption

+0

如果事务处理比指定的超时时间长,该怎么办。我的问题是,在session.set_save_handler中,执行“db_read”方法并在会话中获取锁定后,它不执行“db_write”方法。不知道是什么原因。 – user1040730 2012-03-17 01:00:13

0

你的情况的主要问题是,你中SessionHandlerInterface :: write方法提交。但是写入方法并不总是执行,例如当使用session_destroy时,它调用SessionHandlerInterface :: destroy方法。因此,您的事务不会被提交并保持打开状态,从而阻止对同一会话的其他并发请求超过必要时间。正确的方法是在SessionHandlerInterface :: close中提交事务,这个事务总是在最后执行。

顺便说一下,有一个在Symfony的数据库的一个PHP会话处理器实现支持不同的锁定策略,并支持大多数数据库系统,如MySQL和PostgreSQL,Oracle和Mssql中:https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php

但要注意的是死锁和锁等待超时可以仍然发生,但不太可能。从我的研究中,基本上有三个选项可以解决这个问题:

  1. 捕获错误并重试交易,希望当时释放锁。在使用Doctrine时,请参考https://github.com/doctrine/dbal/pull/718了解一些实现的想法和讨论。
  2. 增加超时时间,例如innodb_lock_wait_timeout这可能有助于根据数据库负载。
  3. 通过捕获异常并通知用户他必须刷新页面才能恢复会话,从而忽略死锁或超时。通常,当多次并行请求同一会话时,即同一用户的许多并行请求,会发生锁定超时。这是一种非标准的用户行为,更可能由脚本或性能测试引起。所以忽略你身边的错误并为用户显示一个错误可能是一个合理的方法。