前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Mysql死亡笔记的死锁记录

Mysql死亡笔记的死锁记录

原创
作者头像
杨不易呀
修改2023-10-06 14:05:17
3840
修改2023-10-06 14:05:17
举报
文章被收录于专栏:杨不易呀

死锁记录

线上MySQL死锁了,我赶紧登录线上系统,查看业务日志。

image.png
image.png

能清楚看到是这条insert语句发生了死锁。

MySQL如果检测到两个事务发生了死锁,会回滚其中一个事务,让另一个事务执行成功。很明显,我们这条insert语句被回滚了。

代码语言:txt
复制
insert into user (id, name, age) values (6, '张三', 6); 

但是我们怎么排查这个问题呢?

到底跟哪条SQL产生了死锁?

好在MySQL记录了最近一次的死锁日志,可以用命令行工具查看:

代码语言:txt
复制
show engine innodb status; 
image.png
image.png

在死锁日志中,可以清楚地看到这两条insert语句产生了死锁,最终事务2被会回滚,事务1执行成功。

事务1

代码语言:txt
复制
insert into user (id,name,age) values (5,'张三',5); 

事务2

代码语言:txt
复制
insert into user (id,name,age) values (6,'李四',6); 

这两条insert语句,怎么看也不像能产生死锁,我们来还原一下事发过程。

先看一下对应的Java代码:

代码语言:java
复制
@Override
@Transactional(rollbackFor = Exception.class)
public void insertUser(User user) {
    // 如果userId不存在,就插入数据,否则更新     
    User userResult = userMapper.selectByIdForUpdate(user.getId());   
    if (userResult == null) {
        userMapper.insert(user);
    } else {
        userMapper.update(user);
    }
}

业务逻辑代码很简单,如果userId不存在,就插入数据,否则更新user对象数据。

从死锁日志中,我们看到有两条insert语句,很明显userId=5和userId=6的数据都不存在。

所以对应的SQL执行过程,可能就是这样的:

image.png
image.png

先用for update加上排他锁,防止其他事务修改当前数据,然后再insert数据,最后发生了死锁,事务2被回滚。

两个事务分别在两个主键ID上面加锁,为什么会产生死锁呢?

如果看过上篇文章,就会明白。

当id=5存在这条数据时,MySQL就会加Record Locks(记录锁),意思就是只在id=5这一条记录上加锁。

当id=5这条记录不存在时,就会锁定一个范围。

假设表中的记录是这样的:

id

name

age

1

王二

1

10

一灯

10

代码语言:txt
复制
select * from user where id=5 for update; 

这条select语句锁定范围就是 (1, 10]。

最后两个事务的执行过程就变成了:

image.png
image.png

通过这个示例看到,两个事务都可以先后锁定 (1, 10]这个范围,说明MySQL默认加的临键锁的范围是可以交叉的。

那怎么解决这个死锁问题呢?

我能想到的解决办法就是,把这两个语句select和insert,合并成一条语句:

代码语言:txt
复制
insert into user (id,name,age) values (5,'张三',5) 	
on duplicate key update name='张三',age=5; 

大家有什么好的解决办法吗? 评论区给出您宝贵的意见!!

最后

本期结束咱们下次再见👋~

🌊 关注我不迷路,如果本篇文章对你有所帮助,或者你有什么疑问,欢迎在评论区留言,我一般看到都会回复的。大家点赞支持一下哟~ 💗

我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

输入图片说明
输入图片说明

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 死锁记录
  • 事务1
  • 事务2
  • 最后
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档