进阶 | MySQL 死锁案例解析一则

这里一共四把锁,加锁步骤如下:

1、在非唯一索引(name)上找到(ddd,29)的索引项,加上X锁;

2、根据(ddd,29)找到主键索引的(29,ddd)记录,加X锁;

3、在非唯一索引(name)上找到(ddd,37)的索引项,加上X锁;

4、根据(ddd,29)找到主键索引的(37,ddd)记录,加X锁;


从上面步骤可以看出,InnoDB对于每个符合条件的记录是分步加锁的,即先加二级索引再加主键索引;其次是按记录逐条加锁的,即加完一条记录后,再加另外一条记录,直到所有符合条件的记录都加完锁。那么锁什么时候释放呢?答案是事务结束时会释放所有的锁。

小结:MySQL 加锁和索引类型有关,加锁是按记录逐条加,另外加锁也和隔离级别有关。
四、疑问点排查及分析思路
1、发生死锁的表结构及索引情况(隐去了部分无关字段和索引):
如下:

    CREATE TABLE `A` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
      `create_date` datetime NOT NULL , 
      `modified_date` datetime NOT NULL ,  
      `pay_name` varchar(256) NOT NULL ,  
      `pay_version` varchar(256) DEFAULT NULL , 
    `identifier` varchar(256) NOT NULL ,
      `seller_id` varchar(64) NOT NULL , 
    `state` varchar(64) DEFAULT NULL ,
      `fund_transfer_ order_ no` varchar(256) DEFAULT NULL,  
    PRIMARY KEY (`id`),UNIQUE KEY `uk_scene_identifier`
    (KEY `idx_seller` (`seller_id`),
    KEY `idx_seller_transNo` (`seller_id`,`fund_transfer_order_no`(20))
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ; 

    该表共有三个索引,1个主键索引,2个普通索引。
    2、分析死锁日志
    发生死锁,第一时间查看死锁日志,内容如下: