利用背景:
利用A,springboot2+shardingJdbc5.1架构, 应用mysql数据库,其中有些订单表为分区表,按日分区。
问题形容
今日在生产环境保护分区表分区时,利用报了死锁。具体日志如下
找到DBA去排查时,基于他们的教训,他们也不抵赖这是利用的死锁,反而狐疑是咱们的利用代码或者JDBC有问题,这 ...
问题复现
在排查相干材料后,我判定了是mysql的锁的机制的问题,于是我做了个测试
利用: session1 客户端: session2session1: 开启事务,并执行查问,持有 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操作改写成软提交形式, 获取不到锁后,开释曾经拿到的锁,而后一直重试
以上,仅代表个人观点,大家有计划能够评论区交换,欢送大家批评指正