出现死锁后,执行show engine innodb status命令得到的部分输出。这个命令会输出很多信息,有一节LATESTDETECTED DEADLOCK,就是记录的最后一次死锁信息。

transaction script架构_死锁

 

我们来看看这图中的几个关键信息。

  1. 这个结果分成三部分:
  • (1) TRANSACTION,是第一个事务的信息;
  • (2) TRANSACTION,是第二个事务的信息;
  • WE ROLL BACK TRANSACTION (1),是最终的处理结果,表示回滚了第一个事务。
  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)这一行的锁。
  • 当然你是知道的,既然出现死锁了,就表示这个事务也占有别的锁,但是没有显示出来。别着急,我们从第二个事务的信息中推导出来。
  1. 第二个事务显示的信息要多一些:
  • “ 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)这个记录锁。

从上面这些信息中,我们就知道:

  1. “lock in share mode”的这条语句,持有c=5的记录锁,在等c=10的锁;
  2. “for update”这个语句,持有c=20和c=10的记录锁,在等c=5的记录锁。

因此导致了死锁。这里,我们可以得到两个结论:

  1. 由于锁是一个个加的,要避免死锁,对同一组资源,要按照尽量相同的顺序访问;
  2. 在发生死锁的时刻,for update 这条语句占有的资源更多,回滚成本更大,所以InnoDB选择了回滚成本更小的lock in share mode语句,来回滚。