哪个查询导致了死锁,尝试重启事务。

5

我无法确定哪个查询导致了Deadlock found when trying to get lock; try restarting transaction错误。 我的mysql包装器有以下几行代码

if (mysql_errno($this->conn) == 1213) {
  $this->bug_log(0,"Deadlock. SQL:".$this->sql);
}

这里涉及到 bug_log 写入文件的问题。

与此相关的 bug 日志文件没有死锁错误,但是 /var/log/mysqld.log 文件中有多条记录:

111016  3:00:02 [ERROR] /usr/libexec/mysqld: Deadlock found when trying to get lock; try restarting transaction
111016  3:00:02 [ERROR] /usr/libexec/mysqld: Sort aborted
111016  3:00:02 [ERROR] /usr/libexec/mysqld: Deadlock found when trying to get lock; try restarting transaction
111016  3:00:02 [ERROR] /usr/libexec/mysqld: Sort aborted
111016  3:00:02 [ERROR] /usr/libexec/mysqld: Deadlock found when trying to get lock; try restarting transaction
111016  3:00:02 [ERROR] /usr/libexec/mysqld: Sort aborted

我该如何追踪它?
2个回答

9

如果另一个事务等待当前事务完成,带有非唯一列的WHERE子句的更新将导致死锁。以下是一个快速测试:

CREATE TABLE test (pk int PRIMARY KEY, a int);
INSERT INTO test VALUES (0, 0);
INSERT INTO test VALUES (1, 0);

会话 1

BEGIN;
SELECT a FROM test WHERE pk=0 FOR UPDATE;

第二节

BEGIN;
SELECT a FROM test WHERE pk=0 FOR UPDATE;

现在阻塞了第二个会话(Session 2)。

会话1(Session 1)

UPDATE test SET a=1 WHERE a>0;

第二个会话中出现了错误。

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

如果在UPDATE语句的WHERE子句中仅使用主键列,则不会出现错误。


你说的“只使用主键列”是什么意思?这不就是你在示例中所做的吗? - Mikhail
1
在更新的WHERE子句中,我有"a>0"。如果我在那里写入"pk=0"(或者任何只使用唯一列的内容),我就不会收到错误。 - Petko Petkov
2
我认为这是我第一次真正理解死锁和普通块的区别。 - Mikhail

3
我曾经看到在以下一种或多种情况下发生了这个问题:
  1. 在查询中多次使用同一表进行连接(SELF JOIN)。
  2. 使用同时对同一表进行多种操作的查询事务。
  3. 在使用事务并将同一表用作SELF JOIN或子查询时。
这可能很难追踪,但基本上是说一个查询防止另一个查询运行,从而防止第一个查询完成等等... http://en.wikipedia.org/wiki/Deadlock

我有一个嵌套查询,但不是在自身上。为什么每次都会导致死锁呢? - Mikhail
你是否正在使用事务?如果两个事务正在处理同一张表但是不同的关键字,也会导致这种情况发生。例如 UPDATE TABLE ... WHERE group_id=X AND user_id=YUPDATE TABLE ... WHERE user_id=Y AND group_id=X,假设它们是不同的关键字。你可以看到,如果它们同时运行,它们将锁定另一个查询返回的其他索引,从而导致死锁。我建议检查你的查询,并确保在处理任何索引时编写它们的顺序相同。 - methodin
可能是,但我怎么找到其他查询呢?目前我已经追踪了这个死锁查询:UPDATE players SET chatban = chatban - 1 WHERE recent=1 and chatban > 0 这怎么可能呢? - Mikhail
查找所有使用玩家的其他查询并比较这些查询。也许您正在选择其中一个WHERE chatban>0 AND recent=1,这可能会导致它。 - methodin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接