记一次排查线上MySQL死锁过程,不能只会curd,还要知道加锁原理
昨晚我正在床上睡得着着的,突然来了一条短信。
啥,线上MySQL死锁了,我赶紧登录线上系统,查看业务日志。
能清楚看到是这条insert语句发生了死锁。
MySQL如果检测到两个事务发生了死锁,会回滚其中一个事务,让另一个事务执行成功。很明显,我们这条insert语句被回滚了。
insert into user (id, name, age) values (6, '张三', 6);
但是我们怎么排查这个问题呢?
到底跟哪条SQL产生了死锁?
好在MySQL记录了最近一次的死锁日志,可以用命令行工具查看:
show engine innodb status;
在死锁日志中,可以清楚地看到这两条insert语句产生了死锁,最终事务2被会回滚,事务1执行成功。
# 事务1
insert into user (id,name,age) values (5,'张三',5);
# 事务2
insert into user (id,name,age) values (6,'李四',6);
这两条insert语句,怎么看也不像能产生死锁,我们来还原一下事发过程。
先看一下对应的Java代码:
@Override
@Transactional(rollbackFor = Exception.class)
public void insertUser(User user) {
User userResult = userMapper.selectByIdForUpdate(user.getId());
// 如果userId不存在,就插入数据,否则更新
if (userResult == null) {
userMapper.insert(user);
} else {
userMapper.update(user);
}
}
业务逻辑代码很简单,如果userId不存在,就插入数据,否则更新user对象数据。
从死锁日志中,我们看到有两条insert语句,很明显userId=5和userId=6的数据都不存在。
所以对应的SQL执行过程,可能就是这样的:
先用for update加上排他锁,防止其他事务修改当前数据,然后再insert数据,最后发生了死锁,事务2被回滚。
两个事务分别在两个主键ID上面加锁,为什么会产生死锁呢?
如果看过上篇文章,就会明白。
当id=5存在这条数据时,MySQL就会加Record Locks(记录锁),意思就是只在id=5这一条记录上加锁。
当id=5这条记录不存在时,就会锁定一个范围。
假设表中的记录是这样的:
id | name | age |
---|---|---|
1 | 王二 | 1 |
10 | 一灯 | 10 |
select * from user where id=5 for update;
这条select语句锁定范围就是 (1, 10]。
最后两个事务的执行过程就变成了:
通过这个示例看到,两个事务都可以先后锁定 (1, 10]这个范围,说明MySQL默认加的临键锁的范围是可以交叉的。
那怎么解决这个死锁问题呢?
我能想到的解决办法就是,把这两个语句select和insert,合并成一条语句:
insert into user (id,name,age) values (5,'张三',5)
on duplicate key update name='张三',age=5;
大家有什么好办法吗?
这个死锁情况,还是挺常见的,赶紧回去翻一下项目代码有没有这样的问题。
文章持续更新,可以微信搜一搜「 一灯架构 」第一时间阅读更多技术干货。
记一次排查线上MySQL死锁过程,不能只会curd,还要知道加锁原理的更多相关文章
- 一次线上mysql死锁分析
一.现象 发运车次调用发车接口时发生异常,后台抛出数据库死锁日志. 二.原因分析 通过日志可以看出事务T1等待 heap no 8的行锁 (X locks 排他锁) 事务T2持有heap no 8的行 ...
- 记一次linux通过jstack定位CPU使用过高问题或排查线上死锁问题
一.java定位进程 在服务器中终端输入命令:top 可以看到进程ID,为5421的cpu这列100多了. 记下这个数字:5421 二.定位问题进程对应的线程 然后在服务器中终端输入命令:top -H ...
- 原创 记录一次线上Mysql慢查询问题排查过程
背景 前段时间收到运维反馈,线上Mysql数据库凌晨时候出现慢查询的报警,并把原始sql发了过来: --去除了业务含义的sql update test_user set a=1 where id=1; ...
- 线上Mysql数据库崩溃事故的原因和处理
前文提要 承接前文<一次线上Mysql数据库崩溃事故的记录>,在文章中讲到了一次线上数据库崩溃的事件记录,建议两篇文章结合在一起看,不至于摸不着头脑. 由于时间原因,其中只讲了当时的一些经 ...
- Spring+SpringMVC+MyBatis+easyUI整合进阶篇(八)线上Mysql数据库崩溃事故的原因和处理
前文提要 承接前文<一次线上Mysql数据库崩溃事故的记录>,在文章中讲到了一次线上数据库崩溃的事件记录,建议两篇文章结合在一起看,不至于摸不着头脑. 由于时间原因,其中只讲了当时的一些经 ...
- Linux命令排查线上问题常用的几个
排查线上问题常用的几个Linux命令 https://www.cnblogs.com/cjsblog/p/9562380.html top 相当于Windows任务管理器 可以看到,输出结果分两部分, ...
- 记一次线上MySQL数据库死锁问题
最近线上项目报了一个MySQL死锁(DealLock)错误,虽说对业务上是没有什么影响的,由于自己对数据库锁这块了解不是很多,之前也没怎么的在线上碰到过.这次刚好遇到了,便在此记录一下 ...
- 一则线上MySql连接异常的排查过程
Mysql作为一个常用数据库,在互联网系统应用很多.有些故障是其自身的bug,有些则不是,这里以前段时间遇到的问题举例. 问题 当时遇到的症状是这样的,我们的应用在线上测试环境,JMeter测试过程中 ...
- 一次线上Mysql数据库崩溃事故的记录
文章简介 工作这几年,技术栈在不断更新,项目管理心得也增加了不少,写代码的速度也在提升,感觉很欣慰,毕竟是在一直进步,但是过程中也有许许多多的曲折,也踩过了数不尽的坑坑洼洼,从一个连百度都不知道用的萌 ...
随机推荐
- ionic系列教程 2 ---- 安装
开发平台注意点首先,我们需要注意构建Ionic App需要的最低配置:Ionic只支持iOS6 +和Android 4.0 + ,(虽然2.3可以工作,但会有点卡).但是,Android设备众多,可能 ...
- pdf.js 预览文件中文内容丢失
问题: 在.netcore中使用pdf.js,pdf中有部分中文无法显示 在浏览器控制台发现有报错 发现在pdf.view.js中url路径异常,没有指向cmaps文件,于是调整了正确的相对路径 再次 ...
- 音视频基本概念和FFmpeg的简单入门
写在前面 最近正好有音视频编辑的需求,虽然之前粗略的了解过FFmpeg不过肯定是不够用的,借此重新学习下: 基本概念 容器/文件(Conainer/File): 即特定格式的多媒体文件,一般来说一个视 ...
- 02. 树莓派初始配置——安装rz命令
安装rz命令 如果你的ssh工具不带xftp文件上传功能,则需要安装使用ZMODEM协议的rz.sz命令. 1. 用root权限登录 2. 创建下载的目录地址(不创建也行,创建后方便以后文件管理) m ...
- 领域驱动模型DDD(三)——使用Saga管理事务
前言 虽然一直说想写一篇关于Saga模式,在多次尝试后不得不承认这玩意儿的仿制代码真不是我一个菜鸟就能完成的,所以还是妥协般地引用现成的Eventuate Tram Saga框架(虽然我对它一直很反感 ...
- busybox+linux Deplay 手机服务器
环境下载地址: Linux Deplay: https://github.com/meefik/linuxdeploy/releases Busybox : https:/ ...
- Redis 内存满了怎么办?这样设置才正确!
上回在<Redis 数据过期了会被立马删除么?>说到如果过期的数据太多,定时删除无法删除完全(每次删除完过期的 key 还是超过 25%),同时这些 key 再也不会被客户端请求,就无法走 ...
- kali 更换国内源
打开source源 vim /etc/apt/sources.list 没有权限进行更改 获取root 权限 按 i 提示内容: E325: 注意 发现交换文件 "/var/tmp/sour ...
- 【java】错误: 找不到或无法加载主类 Test.class
在配置java环境完成时,在cmd中运行 java -version 可以运行,但是当运行 helloworld 文件时,报错. 两种情况 解决: 1.运行 java helloworld 而不是 ...
- python牛顿法求一元多次函数极值
现在用牛顿法来实现一元函数求极值问题 首先给出这样一个问题,如果有这么一个函数$f(x) = x^6+x$,那么如何求这个函数的极值点 先在jupyter上简单画个图形 %matplotlib inl ...