mysql线上bug的缩小版demo演练

CREATE TABLE`TB_TEST` (`Id`bigint(20) unsigned NOT NULL COMMENT'Id',

`UserId`bigint(20) NOT NULL DEFAULT'0'COMMENT'用戶id',`OrderId`bigint(20) NOT NULL DEFAULT'0'COMMENT'订单号',

PRIMARY KEY (`Id`),KEY`idx_user_order` (`UserId`,`OrderId`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Test'

insert into TB_TEST values(1,1,1);

insert into TB_TEST values(2,10,10);

insert into TB_TEST values(3,10,15);

insert into TB_TEST values(4,15,20);

线程1:begin 但是不commit

delete from TB_TEST where UserId = 10 and OrderId = 10;

线程2:begin 但是不commit

delete from TB_TEST where UserId = 10 and OrderId = 15;

线程1:执行

insert into TB_TEST values(5,10,12);   这个时候这个线程会等待

线程2:执行

insert into TB_TEST values(6,10,13);这个时候会出现死锁的现象

select * from information_schema.INNODB_TRX

出现死锁的原因是

如果一条sql用到了主键索引(mysql主键自带索引),mysql会锁住主键索引;

如果一条sql操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引.

解决方法

这个地方,代码的问题需要根据情况自己去修改,可以试着把索引去掉(有风险),或者在进行update的时候尽量避开非主键索引,我这里记录一下被锁后应该怎么去解决的方法,首先先用sql查询一下mysql的事务处理表

正常情况下的状态都是RUNNING,但是在被锁之后就会变成LOCK WAIT ,一旦出现这种情况,就得杀死这个进程,如果进程杀不死就只能重启Mysql服务了

杀死进程

经验教训

无论前台后台的程序,都不应该存在仅根据非主键的几个字段一查就要update/delete的场景。即使有,也应该改为先把要更新的记录查出来然后逐条按主键id更新。

上一篇:Swagger 文本文档注释展示 Demo


下一篇:(Java蓝桥杯算法)递归方法求Ckn