查看mysql死锁日志
show engine innodb status
找到信息中LATEST DETECTED DEADLOCK这一行,可以看到mysql的死锁信息详情
------------------------
LATEST DETECTED DEADLOCK
------------------------
2021-08-25 14:13:37 0x7facac6b8700
*** (1) TRANSACTION:
TRANSACTION 1589867098, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
LOCK WAIT 508 lock struct(s), heap size 57552, 4 row lock(s)
MySQL thread id 201608808, OS thread handle 140379228206848, query id 3088485657 172.18.119.16 root updating
UPDATE web_viewlog SET viewcount=viewcount+1,lasttime='2021-08-25 14:13:37' WHERE uid=2150174 and kename='21es1mmi'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 564 page no 16179 n bits 208 index PRIMARY of table `zijiebao`.`web_viewlog` trx id 1589867098 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 16; compact format; info bits 0
MySQL有三种锁的级别:页级、表级、行级。
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
行级锁
行级锁在使用的时候并不是直接锁掉这行记录,而是锁索引
如果一条sql用到了主键索引(mysql主键自带索引),mysql会锁住主键索引;
如果一条sql操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引.
什么情况下会造成死锁
所谓死锁<DeadLock>: 是指两个或两个以上的进程在执行过程中,
因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程。
表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB。
收集死锁信息:
- 利用命令 SHOW ENGINE INNODB STATUS查看死锁原因。
- 调试阶段开启 innodb_print_all_deadlocks,收集所有死锁日志。
减少死锁:
- 使用事务,不使用 lock tables 。
- 保证没有长事务。
- 操作完之后立即提交事务,特别是在交互式命令行中。
- 如果在用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),尝试降低隔离级别。
- 修改多个表或者多个行的时候,将修改的顺序保持一致。
- 创建索引,可以使创建的锁更少。
- 最好不要用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE)。
- 如果上述都无法解决问题,那么尝试使用 lock tables t1, t2, t3 锁多张表
解决方法
首先先用sql查询一下mysql的事务处理表
select * from information_schema.INNODB_TRX;
正常情况下的状态都是RUNNING,但是在被锁之后就会变成LOCK WAIT ,
一旦出现这种情况,就得杀死这个进程,如果进程杀不死就只能重启Mysql服务了。
杀死进程
kill 进程ID