在初学者从源码理解MySQL死锁问题中介绍了使用调试MySQL 源码的方式来查看死锁的过程,这篇文章来讲讲一个常见的案例。
这次我们讲一段唯一索引年代锁与X锁的爱恨情仇
我们来看一个简化过的例子
#构造数据 创建表的t1 ( “id”int(11)不是零AUTO_INCREMENT, “名字”varchar (10), “水平”int (11), 主键(“id”), 唯一键“uk_name”(“名字”) ); 插入“t1”(“名字”,“水平”)值(' A ', 0); #出现问题的sql语句如下,并发情况下就会出现死锁 忽略插入“t1”(“名字”,“水平”)值(' A ', 0); 更新t1组水平=1 name=" A "; >之前我们用之前介绍过的源码分析方式,先来看下这两条语句分别加什么锁,然后分析死锁形成的过程。
<强>第一条语句
强>忽略插入t1(名称、级别)值(' A ', 0),在调试中得到的结果如下
![]()
可以看到这条语句对唯一键uk_name加共享锁(锁),而且成功。
<强>第二条语句强>
更新t1组水平=1 name=" A ";>之前,通过唯一键更新数据库字段。
这种情况在之前的文章已经介绍过,<强>会对唯一索引加X锁,然后对主键索引加X锁强>
![]()
![]()
这样就可以非常轻松的复现死锁的问题了,步骤如下
1。开启两个会话,分别开始
2.session1执行插入忽略t1(名称、级别)值(' A ', 0),
3.session2执行插入忽略t1(名称、级别)值(' A ', 0),
4.session1执行更新t1组水平=1 name=" A ";进入等待状态
5.session2执行更新t1组水平=1 name=" A ";,死锁产生,被回滚,同时事务1执行成功详细的锁状态变化如下
t1 t2 备注 忽略插入 - 英国t1成功获得的年代锁DB_SUCCESS - 忽略插入 英国t2成功获得的年代锁DB_SUCCESS 更新 - 英国t1尝试获得的X锁,但没有成功,处于等待状态DB_LOCK_WAIT - 更新 英国t2尝试获得的X锁,发现死锁产生DB_DEADLOCK - 死锁 t2释放锁 成功 - -死锁日志如下:
最新检测到死锁 ------------------------ 181208年23:00:52 * * *(1)事务: 事务53 a7、活跃的162秒指数开始阅读 在使用mysql表1,锁定1 锁等待3锁结构(s),堆大小376,2行锁(s) MySQL线程id 12 0 x700010522000 OS线程处理,查询id 1424 localhost根更新 更新t1组水平=1,name=" A " * * *(1)等待这个锁被授予: 记录锁空间id 89页4 n位72指数的uk_name表“lock_demo2”。t1的硫氧还蛋白id 53 a7 lock_mode X锁rec但不是差距等 记录锁,2号堆物理记录:n_fields 2;紧凑的格式;信息比特0 0:len 1;十六进制41;asc;; 1:len 4;十六进制80000001;asc;; * * *(2)事务: 事务53 a8,活跃8秒指数开始阅读 在使用mysql表1,锁定1 3锁结构(s),堆大小376,2行锁(s) MySQL线程id 96 0 x70001062e000 OS线程处理,查询id 1425根更新本地主机 更新t1组水平=1,name=" A " * * *(2)持有的锁(S): 记录锁空间id 89页4 n位72指数的uk_name表“lock_demo2”。t1 trx id 53 a8锁定模式年代 记录锁,2号堆物理记录:n_fields 2;紧凑的格式;信息比特0 0:len 1;十六进制41;asc;; 1:len 4;十六进制80000001;asc;; * * *(2)等待这个锁被授予: 记录锁空间id 89页4 n位72指数的uk_name表“lock_demo2”。t1的硫氧还蛋白id 53 a8 lock_mode X锁rec但不是差距等 记录锁,2号堆物理记录:n_fields 2;紧凑的格式;信息比特0 0:len 1;十六进制41;asc;; 1:len 4;十六进制80000001;asc;; * * *我们回滚事务(2)通过唯一索引年代锁与X锁来了解MySQL死锁套路