一、构造测试数据
CREATE TABLE `deadlock_test` (
id bigint NOT NULL ,
uid bigint not null,
deleted int not null,
PRIMARY KEY (id),
UNIQUE KEY `uk_uid` (uid)
)
insert into deadlock_test values(1,10,0);
select * from deadlock_test ;
如上所示,这个表只有一条记录。
二、构造死锁
session1 执行如下语句;
begin;
update deadlock_test set deleted = 1 where uid = 10 ;
session2 执行如下语句
begin;
update deadlock_test set uid = 1 where id = 1;
session3 执行如下语句
begin;
update deadlock_test set deleted = 1 where uid = 10 ;
再回到session1 执行
rollback;
这时候死锁产生
执行顺序如下表一样
三、死锁分析
借助 performance_schema.data_locks表来分析死锁的形成
session1执行后,产生两条锁记录
一个是主键索引上的X锁,一个是唯一键索引上的X锁
session2执行后
增加了一个 阻塞的主键锁
session3执行后
增加了一个 阻塞的唯一键锁
回到session1 执行回滚后
session2 与 session3产生了相互等待
session2语句要完成,不仅需要唯一键锁,还要主键锁;
session3语句要完成,不仅需要主键锁,还要唯一键锁;
session2 等待session3的唯一键锁
session3 等待session2的主键锁
至此死锁产生
死锁形成上图。
四、建议
对于表的更新,删除,尽量where条件扫描主键索引。 这样就不会造成死锁,只会阻塞。