乐趣区

关于mysql:Mysql-MDLDDL-死锁

利用背景:

 利用 A,springboot2+shardingJdbc5.1 架构, 应用 mysql 数据库, 其中有些订单表为分区表, 按日分区。

问题形容

 今日在生产环境保护分区表分区时,利用报了死锁。具体日志如下 

找到 DBA 去排查时,基于他们的教训,他们也不抵赖这是利用的死锁,反而狐疑是咱们的利用代码或者 JDBC 有问题,这 …

问题复现

在排查相干材料后,我判定了是 mysql 的锁的机制的问题,于是我做了个测试

 利用:session1   客户端:session2

session1: 开启事务,并执行查问,持有 XXX 对象的 SHARED_READ 锁,简称 SR 锁。session2: 执行增加分区(DDL)命令,想要获取 XXX 对象的 EXCLUSIVE 锁,简称 X 锁.


这个状态时,session2 在等 session1 开释锁。sessin1: 继续执行 update 命令,会申请 XXX 对象的 SHARED_WRITE 锁,简称 SW 锁。这个状态时,session2 在期待获取 XXX 对象的 X 锁,session1 想要申请 SW 锁,必须等 session2 开释掉锁。所以 session1 在等 session2 开释锁。两个会话相互期待,产生死锁,MySQL 数据库会主动回滚其中一个事务。

session1 :

session2:

此刻死锁曾经呈现,咱们来看下数据库里的死锁日志

测试的后果和我料想 or 咱们遇到的一样,是 X 锁和 SW 锁的互相互斥的机制导致的死锁,而这种死锁不会在 mysql 的死锁日志中记录

问题起因

先给大家看一下 mysql 的锁的兼容矩阵

Request   |  Granted requests for lock                  |
 type     | S  SH  SR  SW  SWLP  SU  SRO  SNW  SNRW  X  |
----------+---------------------------------------------+
S         | +   +   +   +    +    +   +    +    +    -  |
SH        | +   +   +   +    +    +   +    +    +    -  |
SR        | +   +   +   +    +    +   +    +    -    -  |
SW        | +   +   +   +    +    +   -    -    -    -  |
SWLP      | +   +   +   +    +    +   -    -    -    -  |
SU        | +   +   +   +    +    -   +    -    -    -  |
SRO       | +   +   +   -    -    +   +    +    -    -  |
SNW       | +   +   +   -    -    -   +    -    -    -  |
SNRW      | +   +   -   -    -    -   -    -    -    -  |
X         | -   -   -   -    -    -   -    -    -    -  |
 依据 mysql 锁兼容矩阵图能够看出,X 锁和任何锁是不兼容的(敲黑板,背下来).

咱们的测试场景下,session2 在期待获取 xxx 对象的 X 锁,session1 想要申请 SW 锁,必须等 session2 开释掉锁。所以 session1 在等 session2 开释锁 , 进而产生死锁 

解决方案

1、在 session1 中的查问,加上 for update, 使得 session1 一开始就获取 SW 锁
2、将 session1 的查问独立出以后事务
3、优化 mysql, 将 DDL 操作改写成软提交形式, 获取不到锁后,开释曾经拿到的锁,而后一直重试

以上,仅代表个人观点,大家有计划能够评论区交换,欢送大家批评指正

退出移动版