Releted:30.答疑文章(二):用动态的观点看加锁.pdf
怎么看死锁?
图 3 是在出现死锁后,执行 show engine innodb status 命令得到的部分输出。这个命令会输出很多信息,有一节 LATESTDETECTED DEADLOCK,就是记录的最后一次死锁信息。

我们来看看这图中的几个关键信息。
-
这个结果分成三部分:
- (1) TRANSACTION,是第一个事务的信息;
- (2) TRANSACTION,是第二个事务的信息;
- WE ROLL BACK TRANSACTION (1),是最终的处理结果,表示回滚了第一个事务。
-
第一个事务的信息中:
WAITING FOR THIS LOCK TO BE GRANTED,表示的是这个事务在等待的锁信息;index c of table test.t,说明在等的是表 t 的索引 c 上面的锁;lock mode S waiting表示这个语句要自己加一个读锁,当前的状态是等待中;Record lock说明这是一个记录锁;n_fields 2表示这个记录是两列,也就是字段 c 和主键字段 id;0: len 4; hex 0000000a; asc ;;是第一个字段,也就是 c。值是十六进制 a,也就是 10;1: len 4; hex 0000000a; asc ;;是第二个字段,也就是主键 id,值也是 10;- 这两行里面的 asc 表示的是,接下来要打印出值里面的“可打印字符”,但 10 不是可打印字符,因此就显示空格。
- 第一个事务信息就只显示出了等锁的状态,在等待 (c=10,id=10) 这一行的锁。
- 当然你是知道的,既然出现死锁了,就表示这个事务也占有别的锁,但是没有显示出来。别着急,我们从第二个事务的信息中推导出来。
-
第二个事务显示的信息要多一些:
“ HOLDS THE LOCK(S)”用来显示这个事务持有哪些锁;index c of table test.t表示锁是在表 t 的索引 c 上;hex 0000000a和hex 00000014表示这个事务持有 c=10 和 c=20 这两个记录锁;WAITING FOR THIS LOCK TO BE GRANTED,表示在等 (c=5,id=5) 这个记录锁。
从上面这些信息中,我们就知道:
“lock in share mode”的这条语句,持有 c=5 的记录锁,在等 c=10 的锁;“for update”这个语句,持有 c=20 和 c=10 的记录锁,在等 c=5 的记录锁。
因此导致了死锁。这里,我们可以得到两个结论:
- 由于锁是一个个加的,要避免死锁,对同一组资源,要按照尽量相同的顺序访问;
- 在发生死锁的时刻,for update 这条语句占有的资源更多,回滚成本更大,所以 InnoDB 选择了回滚成本更小的 lock in share mode 语句,来回滚。
课后补充
死锁日志中锁状态的名称
lock_mode X waiting表示 next-key lock;
lock_mode X locks rec but not gap是只有行锁;
还有一种locks gap before rec,就是只有间隙锁;