MySQL发生死锁时,通过show engine innodb status;命令并不能看到事务中引起死锁的所有SQL语句。
死锁排查起来就比较麻烦,需要查询events_statements_%表,来获取SQL,同时需要对业务也比较熟悉,这样能分析出造成死锁的语句。
本着探究的目的,来看下MySQL死锁检测实现及为何无法打印出触发死锁的所有SQL语句。
Lock bitmap
截取show engine innodb status;命令查询锁信息时一段内容:
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 124 page no 4 n bits 80 index idx_id of table `dhy`.`t` trx id 45909 lock_mode X waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000000000601; asc ;;
space id、page no、n bits(lock_rec_t结构体) 通过这三个可以定位到某一条记录,这里对应的就是heap_no = 2这条。n_bits是一个bitmap,用来记录行记录上是否持有Lock。
lock_t 结构用来描述锁信息的,通过n_bits可以将lock(lock_t类型的变量,下文中都将这样描述)与行记录的对应起来。lock_rec_t结构如下:
struct lock_rec_t {
ib_uint32_t space; /*!< space id */
ib_uint32_t page_no; /*!< page number */
ib_uint32_t n_bits; /*!< number of bits in the lock
bitmap; NOTE: the lock bitmap is
placed immediately after the
lock struct */
/** Print the record lock into the given output stream
@param[in,out] out the output stream
@return the given output stream. */
std::ostream& print(std::ostream& out) const;
};