最近,笔者在查看线上服务日志时,发现spring大量异常,异常中都显示了同样的报错信息,信息如下。

Deadlock found when trying to get lock; try restarting transaction

调研之后发现是mysql发生了死锁,这也是笔者第一次遇到数据库死锁问题,详细研究后,将过程记录为文章,以便日后参考回顾。

1. 死锁

死锁指的是两个或两个以上的进程(线程)在执行的时候,因为争夺资源出现相互等待的一种现象。产生死锁需要同时满足以下四个条件

  1. 互斥条件:一个资源每次只能一个进程使用
  2. 不可抢占:进程1在获取资源,使用的过程中,进程2不能抢占进程1正在使用的资源
  3. 占有且等待:进程在申请资源的时,不能释放已经持有的资源
  4. 循环等待:进程1等待进程2资源,同时进程2等待进程1持有的资源,出现循环等待的情况

2. 死锁日志

为了查找造成死锁的sql语句,笔者通过show engine innodb status查看到最近的一次死锁日志,通过这个sql语句,我们就能确定造成死锁的事务

//事务一相关信息
*** (1) TRANSACTION:
TRANSACTION 50E, ACTIVE 66 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 7, OS thread handle 0x27448, query id 82 localhost 127.0.0.1 root Updating
//当前事务正在执行的sql语句
update tb1 set c1= 10 where id =5
//以下信息记录了锁等待信息
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
//正在申请主键索引行记录的x锁
RECORD LOCKS space id 0 page no 3328 n bits 72 index `PRIMARY` of table `test`.`tb1` trx id 50E lock_mode X locks rec but not gap waiting
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0

//事务2相关信息
*** (2) TRANSACTION:
TRANSACTION 50F, ACTIVE 47 sec starting index read
mysql tables in use 1, locked 1
3 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 8, OS thread handle 0x277e4, query id 83 localhost 127.0.0.1 root Updating
update tb1 set c1= 10 where id =5
//正在持有的锁:主键索引为5的行记录级别的S锁
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 3328 n bits 72 index `PRIMARY` of table `test`.`tb1` trx id 50F lock mode S locks rec but not gap
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 00: len 4; hex 80000005; asc     ;;1: len 6; hex 00000000050d; asc       ;;2: len 7; hex 8b00000d080110; asc        ;;3: len 4; hex 80000005; asc     ;;4: len 4; hex 80000005; asc     ;;*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 3328 n bits 72 index `PRIMARY` of table `test`.`tb1` trx id 50F lock_mode X locks rec but not gap waiting
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 00: len 4; hex 80000005; asc     ;;1: len 6; hex 00000000050d; asc       ;;2: len 7; hex 8b00000d080110; asc        ;;3: len 4; hex 80000005; asc     ;;4: len 4; hex 80000005; asc     ;;WE ROLL BACK TRANSACTION (2)

笔者发现死锁日志最后一行出现了WE ROLL BACK TRANSACTION (2)信息。这是Mysql innodb引擎自动检测死锁机制,MySQL选择打断其中一个事务破坏死锁条件来消除死锁。Mysql官方文档上显示,mysql会选择杀死小的事务,这里的小指的是执行的insert,update,detected语句数目小的事务。需要注意的是mysql innodb死锁检测只能针对innodb引擎级别死锁,innodb死锁检测不能检测到应用层级别死锁

3. 死锁复现

为了避免泄露公司的业务和数据,笔者在开发环境复现了这个死锁

表结构如下所示

事务执行顺序如下

为什么这个sql语句会造成死锁呢?原因如下

4. 解决方案

通过上文的死锁复现,笔者发现事务2和事务3的作用一样的,他们都操作了相同的资源,执行事务2和事务3可能是同一进程内的线程执行,也可能是位于不同进程的线程执行。针对这种情况,笔者在生产环境使用分布式锁解决这种死锁场景,笔者以操作的行记录id作为分布式资源id,关于分布式锁,可以参考笔者先前写的文章

5. 发现死锁

上述场景,Mysql发现了死锁,并选择回滚其中一个事务解决了死锁问题,但是老版本的mysql没有死锁检测机制,如果出现死锁,连接可能都会处于等待状态,直到50S的锁等待超时,这会长时间占据数据库连接,导致数据库连接池连接耗尽,tomcat无法获取数据库连接,一直处于等待状态,随后tomcat队列排满后,整个服务就会处于僵死状态,在生产环境中是非常大的事故。如果发现mysql执行SQL语句长时间不响应。我们可以通过show full processlist 命令查看当前所有数据库连接状态,如果连接在等待锁资源,在State状态会显示waiting for table metadata lock信息,同时可以通过info信息查看数据库连接执行了哪一条sql语句,如果所有的等待锁的连接执行的sql语句都涉及到了同一张表,那么就能断定哪站表发生了死锁

6. 查找连接

知道哪张表被锁定仍然无法解决我们的问题,我们需要知道哪个数据库连接对表加了锁,才能kill连接,从mysql5.5开始,information_schema增加了三个关于锁的表,通过这三张表,我们能够找到连接id

6.1 innodb_locks

这张表提供了各个事务请求的数据库锁但是仍然没有获取的数据库锁。这张表提供的最重要的信息是请求锁的事务id

6.2 innodb_trx

通过这张表我们能查到当前innodb引擎执行的所有事务id以及当前执行事务的数据库连接id,于是便能通过kill命令杀死数据库连接,更关键的是我们能查找到事务正在执行的sql语句

6.3 innodb_lock_waits

这张表中requesting_trx_id代表了申请锁资源的事务ID,requesting_lock_id代表申请的锁id,blocking_trx_id代表了阻塞事务70E的事务id,blocking_lock_id代表了阻塞事务70E的锁的ID

出现死锁后,我们可以通过innodb_lock_waits获取相互等待的事务id,通过事务id从innodb_trx查找到数据库连接id,然后使用kill杀死连接

7. 应用层死锁

innodb_locks,innodb_trx,innodb_lock_waits三张表只能查找到innodb引擎层死锁的数据库连接id,对于server层死锁就无能为力了。比如说下述命令加的锁

lock tables tb1 write;
flush tables with read lock;

针对这种死锁,无法通过杀死数据库连接id达到释放锁的目的,针对这种情况笔者尚未找到解决方案,在生产环境下,笔者也遇到过这种情况造成的死锁,笔者只能寻求DBA重启数据库可以暂时解决死锁问题,但是最好的解决方案是尽量不要使用手动加锁命令。

mysql 命令 kill_MySQL之死锁检测相关推荐

  1. 10、MySQL锁等待,死锁,死锁检测

    使用数据库时,有时会出现死锁.对于实际应用来说,就是出现系统卡顿. 死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象.就是所谓的锁资源请求产生了回路现象,即死循环,此时称 ...

  2. mysql死锁检测算法_MySQL InnoDB如何应付死锁

    死锁是事务处理型数据库系统的一个经典问题,但是它们并不是很危险的, 除非它们如此地频繁以至于你根本处理不了几个事务. 当因死锁而产生了回滚时,你通常可以在你的应用程序中重新发出一个事务即可. Inno ...

  3. 浅析MySQL死锁检测

    MySQL发生死锁时,通过show engine innodb status;命令并不能看到事务中引起死锁的所有SQL语句. 死锁排查起来就比较麻烦,需要查询events_statements_%表, ...

  4. mysql数据库死锁检测_数据库死锁检测和解决方式

    做性能测试或者线上环境并发量比较大的时候经常出现数据库死锁的情况,下面介绍几种数据库死锁的检测方式和解决方式.都是采用sql命令实现的.如果不用命令行也可以通过查看数据库服务器的日志信息进行死锁检测, ...

  5. mysql 死锁和死锁检测

    1.死锁的定义 当mysql请求发生并发时,不同线程执行的事务操作需要获取相同资源的锁,涉及的线程都在等待别的线程释放锁,几个线程都进入无限等待的状态时,就出现死锁了. 2.锁等待的最大时长 当出现死 ...

  6. mysql二级封锁协议_MySQL 行锁、两阶段锁协议、死锁以及死锁检测

    行锁 MySQL的行锁都是在引擎层实现的,但是 MyISAM 不支持行锁,意味着并发控制只能使用表锁,同一张表任何时刻只能被一个更新在执行,影响到业务并发度.InnoDB 是支持行锁的,这也是 MyI ...

  7. 数据库面试题:Mysql如何进行死锁检测

    Mysql如何进行死锁检测 mysql的InndoDB存储引擎使用wair-for graph(等待图)的方式来进行死锁检测. wair-for graph要求数据库保存一下两种信息: 锁的信息链表 ...

  8. linux 内核 死锁 检查,一种linux内核自旋锁死锁检测报告系统和方法与流程

    本发明涉及内核死锁检测领域,具体的说是一种linux内核自旋锁死锁检测报告系统和方法. 背景技术: linux内核死锁是长期困扰内核开发人员的问题之一,但自内核引入lockdep调试模块之后,内核死锁 ...

  9. mysql命令的分类_MySQL常用命令分类汇总

    一.查询状态类 1.查看当前有哪些数据库? mysql> show databases; 2.查看当前数据库有哪些表? mysql> use  database1; mysql> s ...

最新文章

  1. 数据结构--Javascript--排序篇
  2. java 定时_结合真实案例,清晰梳理几种定时任务的退出「JAVA并发」
  3. 机器学习中用到的概率知识_机器学习中有关概率论知识的小结
  4. POJ2594 Treasure Exploration
  5. 蓝牙:深入浅出低功耗蓝牙(BLE)协议栈
  6. bzoj 1263: [SCOI2006]整数划分
  7. 决策树和基于决策树的集成方法(DT,RF,GBDT,XGB)复习总结
  8. 神经网络控制系统设计,神经网络技术及其应用
  9. 微型计算机对应的英文名,跟中文名匹配的英文名
  10. Eclipse 查看类继承和实现关系(包括子类)
  11. android 卸载残留代码,完全卸载AndroidStudio(示例代码)
  12. 泰坦尼克号幸存者逻辑回归预测
  13. mysql查询表的列名_查看表所有列名SQL
  14. Feign原理以及feign调优
  15. 计算机网络怎么查看连接打印机驱动,如何查找打印机驱动的方法-电脑自学网...
  16. RTX3060+ubuntu20.04+cuda11.1+cudnn8.0.5+pytorch1.7.1+tensorflow2.4构建深度学习环境
  17. WebKit 内容整理
  18. 经纬度与WGS84坐标转换
  19. 使用Win32 API获取Windows系统主题色
  20. lua 连接redis集群

热门文章

  1. 详解nohup和 区别
  2. Jquery练习题—实现分组添加功能
  3. java从1开始计时用线程_java – Python – 线程,计时或函数使用?
  4. @FeignClient中的@RequestMapping也被SpringMVC加载的问题解决
  5. 一站式机器学习平台建设实践
  6. Redis系列教程(七):Redis并发竞争key的解决方案详解
  7. 资源征集 | 2021年全国知识图谱与语义计算大会开放资源征集(Resource Track)通知...
  8. UE4从4.15移植到4.16
  9. C++实现树的基本操作,界面友好,操作方便,运行流畅,运用模板
  10. 各大主流.Net的IOC框架性能测试比较