【问题标题】:PDO false positive deadlockPDO 误报死锁
【发布时间】:2020-02-08 16:30:51
【问题描述】:

我们正在 PHP 7.0 和 MariaDB 10.0 上运行基本的 Web 应用程序。每个查询都通过 PDO 类进入数据库。

问题是PDO有时会抛出死锁异常:

SQLSTATE[40001]:序列化失败:1213 尝试获取锁时发现死锁;尝试重启事务

但是当我查看 MariaDB 的死锁规范时(使用 SHOW ENGINE INNODB STATUS),“最后一个死锁”并不是真正的最后一个死锁。例如,从 2019 年 10 月 1 日开始出现死锁,但 PDO 在 2019 年 10 月 5 日向我发出了最后一次死锁的警报。这就像 PDO 正在弥补死锁。但同样 - 这不是每次。当最后一个死锁未显示在“SHOW ENGINE INNODB STATUS”中时,MariaDB 属性“Innodb deadlocks”(int) 不会增加。

此时仅针对一项交易发生。事务中的所有表都在 InnoDB 引擎上运行。大约有 40 个查询(选择、更新、插入)。 MariaDB 属性“innodb 打印所有死锁”已打开。只有一台数据库服务器可以连接。

PDO 只是报告数据库中的所有错误还是可以“弥补死锁”?或者可能是旧版本的 PHP 和 MariaDB 的问题?我们计划升级,但不是现在。

而且可以肯定的是 - 我不是要解决当前的僵局,而是要解决整个异常情况。


编辑:我发现,当前的死锁不是由 PDO “弥补”的。这是真正的死锁,但问题是在其他事务(cron 作业)中使用“TRUNCATE”查询。

详细说明:

让我们假设表 x1 和表 x2 引用 x1 主键。故事是:

  1. 第一个事务:将行插入表 x1;
  2. 第二个事务:TRUNCATE 表 x2; (等待锁定)
  3. 第一个事务:更新表 x1 中插入的行;

第三步导致死锁。即使表 x1 插入行的主键实际上不在表 x2 中。表 x2 只是引用 x1。

【问题讨论】:

  • 整体解决方案见this post
  • 感谢您的回答,但我的问题是关于 PDO 显示的 MariaDB“不记得”一些死锁。我知道,死锁是如何产生的。嗯..主要是:-D
  • 尝试设置系统变量innodb_print_all_deadlocks。这将打印到 MariaDB 配置的错误日志。
  • 我已经说过这个变量已启用 :-) 而且我检查了 MariaDB 日志,它与“SHOW ENGINE INNODB STATUS”相同 - 不存在死锁。
  • 你用的是那个事务隔离模式?

标签: php mysql pdo mariadb deadlock


【解决方案1】:

如果你是TRUNCATEing作为替换内容的步骤,那么改为:

CREATE TABLE x LIKE real;
load data into x
RENAME TABLE real TO old,
             x TO real;
DROP TABLE old;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 2015-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多