MySQL数据库死锁分析
背景说明:
公司内部一套自建分布式交易服务平台,在POC稳定性压力测试的时候出现了数据库死锁。(InnoDB引擎)由于保密性,假设是app_test表死锁了。
现象:
发生异常:Deadlock found when trying to get lock; try restarting transaction
分析思路:
1、回忆和查找相关资料,InnoDB死锁导致的原因。
第一:涉及多表访问,两个事务相互占有对方需要的锁。假设有A表(含有初始化记录1)和B表(含有初始化记录2)。进行如下操作会发生死锁。(先设置set autocommit=0; 不自动提交事务)
事务1: updateA表记录1,where条件带主键索引。 事务2: updateB表记录2 ,where条件带主键索引
事务1:updateB表记录2 ,where条件带主键索引 事务2: updateA表记录1,where条件带主键索引 (Deadlock)
第二:单表单记录访问,两个事务相互占有对方需要的锁。假设有A表(含有初始化记录1) 进行如下操作会发生死锁 (先设置set autocommit=0; 不自动提交事务)
事务1: select A表记录1 lock in share mode where条件带主键索引。 事务2:select A表记录1 lock in share mode where条件带主键索引。
事务2: updateA表记录1 where条件带主键索引 事务2: updateA表记录1 where条件带主键索引 (Deadlock)
2、查看根据死锁的sql语句找到代码逻辑。下面代码逻辑就仅仅以操作数据库的形式体现。(毕竟数据库经过这么多人的验证,先怀疑是否程序操作数据库有问题。)
begin; select liusmc ,huancdx ,buchang ,liuszdz ,liuszxz ,dangqzh from app_test where liusbm = 'chkseq' AND xitongbs = '110' AND farendma = '985' for update; UPDATE app_test SET liusmc = 'chkseq', huancdx = 10000, buchang = 1, liuszdz = 99999999, liuszxz = 0, dangqzh = 3380100 WHERE liusbm = 'chkseq' AND xitongbs = '110' AND farendma = '985' ; commit;
3、根据代码逻辑分析,sql采用的是 for update 添加的排他锁,而且是单表操作,还检查了表的索引情况(此表无索引,此处很关键),于是潜意识里面 排除了,第一和第二个导致死锁的原因。此处又陷入死胡同。能想到的两个原因都排除了。
4、于是想使用show engine innodb status 命令来查询Deadlock的具体信息究竟是那两个事务锁住了什么资源,导致了死锁。但是奈何没有数据库权限。又不好意思直接问甲方的管理员要。所以还是先自己梳理思路,查询相关资料。
5、后来决定模拟下代码逻辑操作数据库的场景。毕竟就一个事务select for update了一个表然后再update,两个事务执行这个的先后顺序,以及查询的是否相同记录也是容易模拟。于是模拟了以下场景。
场景模拟:
1、两个事务,事务1 先select for update 记录1 ,事务2 select for update 记录1 ;事务1 update记录1 (此场景不会死锁)
2、两个事务,事务1 先select for update 记录1 ,事务2 select for update 记录2 ;事务1 update记录1 (居然死锁发生了,不是说InnoDB引擎 在表无索引的情况下是锁表的么?知识范围有缺陷还是深度不够?此时的我真的在心中万马奔腾啊)
思绪良久,翻阅了好多资料,实在想不通了,于是厚着脸皮也不怕影响POC成绩的情况下,请教了甲方老的DBA协助查看下。DBA叫我复现以下,我说明了现象以及原因。然后也复现了。
DBA的回复是:
事务1 持有锁 事务2需要事务1持有的锁,事务1 的update操作需要获取锁,所以出现了回路,发生死锁。外带了一句主要问题where条件多列检测索引。解决方法就是添加索引。由于DBA领导一句话,要是这个原因清楚了,此话题就到此结束。所以没敢多问,环境维护人员漏加索引了(此表本来有主键索引的)。
对于DBA的这个解释,”还是没有懂,事务1持有锁,事务2需要事务1持有的锁。事务1 update操作需要获取这个锁,所以出现了回路,发生了死锁。” 事务2只是在等待这个事务1 占有的锁而已,为何事务1的update操作需要获取锁会被事务2 占有。难道在等待也是算占有的? 如果等待也算是占有的话,那么场景1模拟的也应该会是死锁。所以明显不是。
DBA查看的日志信息的时候给了一个截图很关键,app_test 的索引 gen_clust_index 被锁住了。我觉得原因出在这个隐藏主键上面。InnoDB在表无唯一索引和主键的情况下,会自动创聚焦索引。
select * from information_schema.INNODB_LOCKS;
select * from information_schema.INNODB_LOCK_WAITS;
当两个事务进程 select for update where条件 使用同一个主键的时候,INNODB_LOCKS 会有两个事务进行的锁定信息,INNODB_LOCK_WAITS也会有一条记录,这个问题,以后待补充查证吧。
MySQL数据库死锁分析的更多相关文章
- Mysql数据库死锁分析相关概念
参考博客: mysql死锁问题分析(https://www.cnblogs.com/LBSer/p/5183300.html) mysql insert锁机制(http://yeshaoting.cn ...
- mysql数据库死锁的产生原因及解决办法
这篇文章主要介绍了mysql数据库锁的产生原因及解决办法,需要的朋友可以参考下 数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据库中就会产生多个事务同时存取同 ...
- MySQL 数据库死锁
数据库死锁 死锁的解决办法(1) 执行下面SQL,先查看哪些表被锁住了: select b.owner,b.object_name,a.session_id,a.locked_mode from v$ ...
- Mysql查询语句使用select.. for update导致的数据库死锁分析
近期有一个业务需求,多台机器需要同时从Mysql一个表里查询数据并做后续业务逻辑,为了防止多台机器同时拿到一样的数据,每台机器需要在获取时锁住获取数据的数据段,保证多台机器不拿到相同的数据. 我们My ...
- 记一次线上MySQL数据库死锁问题
最近线上项目报了一个MySQL死锁(DealLock)错误,虽说对业务上是没有什么影响的,由于自己对数据库锁这块了解不是很多,之前也没怎么的在线上碰到过.这次刚好遇到了,便在此记录一下 ...
- 关于在项目中遇到MySQL数据库死锁的问题
在MySQL中, 当一个事务去更新某条数据, 还没有提交的时候, 第二个事务去更新该数据, 则会出现等待获取锁超时异常: >> Lock wait timeout exceeded; tr ...
- mysql数据库死锁的解决方案
1. 查询锁表信息 show OPEN TABLES where In_use > 0;2. 查看当前数据库锁表的情况 SELECT * FROM information_schem ...
- Mybatis-update - 数据库死锁 - 获取数据库连接池等待
最近学习测试mybatis,单个增删改查都没问题,最后使用mvn test的时候发现了几个问题: update失败,原因是数据库死锁 select等待,原因是connection连接池被用光了,需要等 ...
- <转>一个最不可思议的MySQL死锁分析
1 死锁问题背景 1 1.1 一个不可思议的死锁 1 1.1.1 初步分析 3 1.2 如何阅读死锁日志 3 2 死锁原因深入剖析 4 2.1 Delete操作的加锁逻辑 4 2.2 死锁预防策略 5 ...
随机推荐
- 我要进大厂之大数据MapReduce知识点(1)
01 我们一起学大数据 老刘今天分享的是大数据Hadoop框架中的分布式计算MapReduce模块,MapReduce知识点有很多,大家需要耐心看,用心记,这次先分享出MapReduce的第一部分.老 ...
- 网站滑到指定的位置给div添加动画效果
<!DOCTYPE html> <html> <head> <style> .anim-show { width:100px; height:100px ...
- Kafka入门(安装及使用)
Kafka是一种分布式的,基于发布/订阅的消息系统. Kafka的组成包括: Kafka将消息以topic为单位进行归纳. 将向Kafka topic发布消息的程序成为producers. 将预订to ...
- CSP2020 游记
Day -28 后天就初赛了,考了一套模拟题,自闭,心态爆炸,感觉退役不远了 Day -26(初赛) 香农是谁??? 手写随机nth_element与O(n)的哈希表??? 阅读程序T2时间复杂度分析 ...
- locust使用小技巧(v0.13.5)
Windows下载: pip install locustio==0.13.5; 以下基于locust的0.13.5,写文章时时2019年,没想到2020年就大变样了 locust是基于python的 ...
- Logstash使用mongodb插件报错: ArgumentError: wrong number of arguments (given 2, expected 1)
目录 背景 安装插件过程 背景 今天在使用logstash收集日志存储到mongodb的安装过程遇到了个错误,记录下来,错误就是下面这样: 配置文件很简单,由于是测试环境,命令行传入日志输入由ruby ...
- 自己动手实现java数据结构(九) 跳表
1. 跳表介绍 在之前关于数据结构的博客中已经介绍过两种最基础的数据结构:基于连续内存空间的向量(线性表)和基于链式节点结构的链表. 有序的向量可以通过二分查找以logn对数复杂度完成随机查找,但由于 ...
- Kafka入门之consumer
offset存放在_consumer_offsets这个topic下 并且从0-49划分了50个分区: consumer会在kafka集群的所有broker中选择一个broker作为consumer ...
- HBase中Memstore存在的意义以及多列族引起的问题和设计
Memstore存在的意义 HBase在WAL机制开启的情况下,不考虑块缓存,数据日志会先写入HLog,然后进入Memstore,最后持久化到HFile中.HFile是存储在hdfs上的,WAL预写日 ...
- bypass disable_function
windows 1.com组件绕过 <?php$command=$_POST['a'];$wsh = new COM('WScript.shell'); // 生成一个COM对象 Shell.A ...