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 ...
随机推荐
- SSTI Flask
1.什么是SSTI?什么是Flask? SSTI称为服务端模板注入,主要为Python.Java.PHP的框架在使用渲染函数时,由于代码不规范或者对于用户输入过于信任而导致产生了SSTI.类似于S ...
- 追星女孩必备!使用Camtasia制作爱豆视频
制作爱豆视频,我用得比较多的是Camtasia(Windows)教程录制.因为这款软件操作简单,功能强大,用起来相当顺手呢.而且更重要的是,Camtasia有录屏功能,电脑存量不足的情况下,真的很好用 ...
- 【PUPPETEER】初探之执行JavaScript方法(六)
一.知识点 page.evaluate() document.querySelector().value = ''; 二.解析知识点 page.evaluate(),查看puppeteer 的api ...
- LeetCode双周赛#33 题解
5480. 可以到达所有点的最少点数目 #贪心 题目链接 题意 给定有向无环图,编号从0到n-1,一个边集数组edges(表示从某个顶点到另一顶点的有向边),现要找到最小的顶点集合,使得从这些点出发, ...
- jstack测试
1.RUNABLE 2.BLOCKED 3.WAITING/TIMED_WAITING Reference Handler线程与Finalizer线程,这两个线程用于虚拟机处理override了obj ...
- mq消息消费,broker选址
PullRequest.MessageQueue.BrokerName 根据PullRequest.MessageQueue得到brokerId,默认0或者用缓存中的suggest,每次消息拉取后会更 ...
- flink:StreamExecutionEnvironment、DataStream和Transformation与StreamOperator
1.StreamExecutionEnvironment: StreamExecutionEnvironment是构建执行任务环境以及任务的启动的入口,主要具备以下几方面的职责: a.存储全局相关的参 ...
- 华为模拟器ensp老是弹出一堆英文up down,关闭
英文内容: Mar 25 2015 20:38:21-08:00 Huawei DS/4/DATASYNC_CFGCHANGE:OID 1.3.6.1.4.1.2011.5.25.191.3.1 co ...
- IB卡开启EIPOIB做虚拟化桥接使用
步骤1:开启EiPOIB 编辑默认"no"为"yes" /etc/infiniband/openib.conf E_IPOIB_LOAD=yes 步骤2:重启h ...
- uni-app p-table下时间转换的问题
问题描述: 从后台获取时间戳,转成日期格式,出现NaN的问题 uni的p-table插件 解决思路