【发布时间】: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 主键。故事是:
- 第一个事务:将行插入表 x1;
- 第二个事务:TRUNCATE 表 x2; (等待锁定)
- 第一个事务:更新表 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