关于死锁:故障分析-MySQL死锁案例分析
作者:杨奇龙 网名“北在北方”,资深 DBA,次要负责数据库架构设计和运维平台开发工作,善于数据库性能调优、故障诊断。 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 一 背景死锁,其实是一个很有意思也很有挑战的技术问题,大略每个DBA和局部开发同学都会在工作过程中遇见 。 本次分享的一个死锁案例是 波及通过辅助索引的更新以及通过主键删除导致的死锁。心愿可能对想理解死锁的敌人有所帮忙。 二 案例剖析2.1 业务逻辑select for update 表记录并加上 x 锁,查问数据,做业务逻辑解决,而后删除该记录。还有其余业务逻辑要更新记录,导致死锁。 2.2 环境阐明数据库 MySQL 8.0.30 事务隔离级别 REPEATABLE-READ create table dl(id int auto_increment primary key,c1 int not null ,c2 int not null,key idx_c1(c1));insert into dl(c1,c2) values (3,1),(3,2),(3,2),(3,3),(4,4),(5,5);2.3 测试用例 2.4 死锁日志------------------------LATEST DETECTED DEADLOCK------------------------2022-12-03 16:43:59 140261132850944*** (1) TRANSACTION:TRANSACTION 1416764, ACTIVE 15 sec starting index readmysql tables in use 1, locked 1LOCK WAIT 5 lock struct(s), heap size 1128, 3 row lock(s)MySQL thread id 15, OS thread handle 140261086668544, query id 283 localhost msandbox updatingupdate dl set c2=10 where c1=5*** (1) HOLDS THE LOCK(S):RECORD LOCKS space id 49 page no 5 n bits 80 index idx_c1 of table `test`.`dl` trx id 1416764 lock_mode XRecord lock, heap no 8 PHYSICAL RECORD: n_fields 2; compact format; info bits 0*** (1) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 49 page no 4 n bits 80 index PRIMARY of table `test`.`dl` trx id 1416764 lock_mode X locks rec but not gap waitingRecord lock, heap no 7 PHYSICAL RECORD: n_fields 5; compact format; info bits 32*** (2) TRANSACTION:TRANSACTION 1416759, ACTIVE 23 sec updating or deletingmysql tables in use 1, locked 1LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 1MySQL thread id 16, OS thread handle 140261085611776, query id 286 localhost msandbox updatingdelete from dl where id=6*** (2) HOLDS THE LOCK(S):RECORD LOCKS space id 49 page no 4 n bits 80 index PRIMARY of table `test`.`dl` trx id 1416759 lock_mode X locks rec but not gapRecord lock, heap no 7 PHYSICAL RECORD: n_fields 5; compact format; info bits 32*** (2) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 49 page no 5 n bits 80 index idx_c1 of table `test`.`dl` trx id 1416759 lock_mode X locks rec but not gap waitingRecord lock, heap no 8 PHYSICAL RECORD: n_fields 2; compact format; info bits 0*** WE ROLL BACK TRANSACTION (2)2.5 死锁剖析sess1 开启一个事务,在T2 时刻执行 select for update,持有id=6的lock_mode X record lock.sess2 在T3 时刻执行依据c1=5的更新,然而其加锁程序是先在索引idx_c1上加锁,顺利加锁,而后到申请加主键上加id=6的锁,发现sess1曾经持有主键 id=6 的X的锁,因而须要期待。如日志中 (1) TRANSACTION: 中 WAITING FOR的提醒 RECORD LOCKS space id 49 page no 4 n bits 80 index PRIMARY of table test.dl trx id 1416764 lock_mode X locks rec but not gap waitingsess1 执行 delete id=6 的操作,因为事务自身曾经持有了主键上的锁,删除记录同时要对索引idx_c1上的记录加上 lock_mode X record lock,发现该锁曾经被sess2持有,造成了死锁条件,sess1 报错,产生回滚。2.6 如何解决本文中死锁的起因是因为 sess2 通过辅助索引进行更新,因而举荐的防止死锁计划是把sess2 应用辅助索引的更新改成基于主键进行更新,从而防止申请idx_c1上的加锁造成循环期待产生死锁。 ...