博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
记一次数据库死锁
阅读量:4937 次
发布时间:2019-06-11

本文共 1183 字,大约阅读时间需要 3 分钟。

业务新上了一个功能,在发布的过程中,系统报出了数据库死锁异常:

com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

死锁发生在一个事务中,事务对多个表进行了操作。在报错日志中,死锁发生在tableA与tableB。一开始怀疑此次发布的某个改动中对上面这两张表新增了select或update操作。将注意力用在排查这个问题上。排查后发现没有相关的变更,又猜测是否是由于更改造成并发请求进来,接口原来是有加分布式锁的,需求更改中缩小了分布式锁的粒度,确实是有可能造成并发请求。但很快又否定了,秒杀场景下的并发量尚且不会发生死锁,何况是这个接口?觉得问题应该别有所在。先回滚了需求后,联系dba执行了命令SHOW ENGINE INNODB STATUS将死锁日志拉取了出来:

610439-20190404090737146-438656407.png

从死锁日志可以看到事务(1)TRANSACTION尝试更新表A,等待表A的锁(1)WATING FOR THIS LOCK TO BE GRANTED.但此时另外一个事务(2)TRANSACTION已经持有了表A的锁:(2)HOLDS THE LOCK(S),同时也在等待表B的锁(2)WATING FOR THIS LOCK TO BE GRANTED. 情况可能如下所示:

事务(1) 事务(2)
持有表1的写锁,并更新了表1
等待表1的写锁
等待表2的写锁

由于事务2一直都获取不到表2的写锁,事务2无法提交,因此事务2持有的表1锁没有释放(在事务执行过程中,如果有加锁操作,这个锁需要等事务提交时释放),导致事务1一直在等待表1的写锁,从而最终导致死锁。那么表2的写锁被哪个事务持有了?有没有可能是事务1?也即是下面这种情况:

事务(1) 事务(2)
持有表2的写锁,并更新了表2
持有表1的写锁,并更新了表1
等待表1的写锁
等待表2的写锁

由于更新的是同一个用户的同一行记录,这种情况可能在sql执行顺序不一致所导致,所以对比了需求变更前后的事务逻辑,果然发现了端倪:

变更前:

事务开始「    更新表1    更新表2」事务提交

变更后:

事务开始「    更新表2    更新表1」事务提交

在发布的过程中,有部分机器的代码处于变更前,有部分机器的代码处于变更后,最终导致了上述的死锁问题。此时原因已经明了,但是疑惑的是为什么死锁出现时马上就报错,不会进行等待?查阅文档发现:死锁检测开了后,发生死锁会立马回滚。死锁检测关闭,锁等待超时时间这个设置才会生效:

610439-20190404090803338-676589670.png

转载于:https://www.cnblogs.com/QG-whz/p/10652940.html

你可能感兴趣的文章
Jquery特效
查看>>
web服务器
查看>>
EV: Workaround to Allow Only One Instance or Window of outlook
查看>>
数据校验,
查看>>
IntelliJ IDEA完美解决tomcat8+乱码问题
查看>>
GDI+ ColorMatrix的完全揭秘
查看>>
破解电信光猫华为HG8120C关闭路由功能方法
查看>>
在Qt示例项目的C ++ / QML源中的//! [0]的含义是什么?
查看>>
【智能家居篇】wifi网络接入原理(上)——扫描Scanning
查看>>
操作引入xml文件的书包(定位到指定节点)
查看>>
操作系统学习笔记系列(一)- 导论
查看>>
已计划将多个默认网关用于提供单一网络
查看>>
CSS实例:图片导航块
查看>>
python进阶七_文件操作(三)
查看>>
window的对象有哪些(笔记)
查看>>
成绩查询方法指引Pmp
查看>>
Boolean Expressions
查看>>
They Are Everywhere
查看>>
数据结构--汉诺塔递归Java实现
查看>>
day14 多态与抽象
查看>>