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更新。