01. MySQL 事务死锁现象及原因初步判断
做IT的几乎每天都接触 MySql,但是 Mysql 事务死锁却并不常见,前段时间就让我遇到了 。异常日志如下
![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/2230004338-0.jpg)
文章插图
从日志看是发生了 Lock wait timeout exceeded 异常 。
Lock wait timeout exceeded:后提交的事务等待前面处理的事务释放锁,但是在等待的时候超过了mysql的锁等待时间,就会引发这个异常 。
PreparedStatementCallback; SQL [UPDATE sf_wx_keyword_ruleSET status = ?,last_update_time = last_update_timeWHERE id = ?];Lock wait timeout exceeded;try restarting transaction;
发生异常的代码主要逻辑如下![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/223000N07-1.jpg)
文章插图
![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/22300021T-2.jpg)
文章插图
分析后其实是因为一个处理流程里开了两个事务,并更新的同一条数据,导致的事务间死锁 。
外层方法通过@Transactional 开启了事务1(@t1),对 sf_wx_keyword_rule 一条数据做更新,内层方法通过 REQUIRES_NEW 又开启了一个新事务2(@t2),并对sf_wx_keyword_rule 的同一条数据做更新 。
begin @t1;UPDATE table SET status = ? WHERE id = 1begin @t2;UPDATE table SET status = ? WHERE id = 1commit @t2;commit @t1;
结论:由于 @t1 和 @t2 更新的是同一条数据,所以 @t2 的执行需要依赖 @t1 的提交,而@t1 的提交又需要 @t2 执行完 。所以两个事务互相等待对方提交导致死锁 。02. 复现及深层原因追踪2.1 复现
为了搞清楚事务死锁,及死锁期间 MySql 的数据状态,新建 test1 表重复上述操作
![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/2230002b1-3.jpg)
文章插图
![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/2230001242-4.jpg)
文章插图
过了大概 30s @t2 返回锁超时,与异常日志一致 。
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
2.2 原因追踪2.2.1 事务状态Mysql 事务操作会涉及到三张表//当前正在执行的每个事务的信息information_schema.innodb_trx//当前事务持有的锁记录information_schema.innodb_locks// 当前被阻塞的事务锁记录information_schema.innodb_lock_waits
查询 innodb_trx 表![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/2230001I9-5.jpg)
文章插图
主要字段的含义
![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/2230003V9-6.jpg)
文章插图
当前有两个未提交的事务,trx_id=21245712 状态为 LOCK WAIT,这条事务产生了一个 id为 21245712:565:3:2 (innodb_locks 表的id) 的锁,也就是该事务的 LOCK因为被阻塞而导致事务超时 。
trx_id = 21245684 是执行完 SQL 还未提交的事务 。
2.2.2 MySql 锁
- innodb_locks InnoDB 锁记录
![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/2230005024-7.jpg)
文章插图
主要字段含义
![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/2230001a6-8.jpg)
文章插图
锁在 MySql 事务里是非常主要的,上面的事务就是通过 Primary (主键) 在 Record (行) 上加的X (写) 锁,先加的 X 锁会成功,后加的 X 锁就会被阻塞 。下面详细了解一下几个主要的锁 。
基本锁
InnoDB 行级锁,分为共享锁(S)和独占锁(X)
- 共享锁(Sharaed Locks: S锁),或叫读锁
- mysql允许拿到S锁的事务读一行
- 加了S锁记录,允许其他事务再加S锁,不允许其他事务再加X锁
- 语法:select ... lock in share mode;
- 独占锁(Exclusive Locks:X锁)或叫写锁
- mysql允许拿到X锁的事务更新或删除一行
- 加了X锁的记录,不允许其他事务再加X锁或S锁
- 语法:select … for update;
延伸一下,有 X 锁之后,我们还能正常的读数据吗?答案是可以的 。
select * from test1;
普通的 SELECT 语句上没有加锁,只有 select ... lock in share mode; 才会加 S 锁 。![线上 MySql 事务死锁,应该怎么排查解决?](http://img.jiangsulong.com/220424/2230003501-9.jpg)
文章插图
推荐阅读
- Word文档打横线,如何在word的横线上打字 不改变横线-
- 新手教程,Linux系统下MySQL的安装
- JDBC+MySQL入门增删改查实战
- 青岛市|至真至美 — 王庭树油画线上云个展
- 搭建mysql主从并用springboot读写分离-含源码
- MySQL如何删除重复数据
- MySQL运行机制
- MySQL5.7数据库主从架构部署,你再也不用去问度娘了
- MySQL高可用架构的演进
- CENTOS Mysql5.7数据库自动安装脚本