mysql数据库死锁:Deadlock found when trying to get lock; try restarting transaction

2021-08-26 17:06:47 浏览数 (10510)

查看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 `w3cschool`.`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


收集死锁信息:

  1. 利用命令 SHOW ENGINE INNODB STATUS查看死锁原因。
  2. 调试阶段开启 innodb_print_all_deadlocks,收集所有死锁日志。

减少死锁:

  1. 使用事务,不使用 lock tables 。
  2. 保证没有长事务。
  3. 操作完之后立即提交事务,特别是在交互式命令行中。
  4. 如果在用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),尝试降低隔离级别。
  5. 修改多个表或者多个行的时候,将修改的顺序保持一致。
  6. 创建索引,可以使创建的锁更少。
  7. 最好不要用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE)。
  8. 如果上述都无法解决问题,那么尝试使用 lock tables t1, t2, t3 锁多张表

 

解决方法

首先先用sql查询一下mysql的事务处理表

select * from information_schema.INNODB_TRX;



正常情况下的状态都是RUNNING,但是在被锁之后就会变成LOCK WAIT ,

一旦出现这种情况,就得杀死这个进程,如果进程杀不死就只能重启Mysql服务了。


杀死进程

kill 进程ID