进阶 | 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、分析死锁日志
发生死锁,第一时间查看死锁日志,内容如下: