死锁浅析

7 篇文章 1 订阅
1 篇文章 0 订阅

1.锁的分类

图片: https://uploader.shimo.im/f/s2uumtE3Go05l0p2.png

首先记住一个基本点,锁是对表的索引的节点进行锁,而不是对某行锁,当走不了索引时候可能就会锁表了。

1.1锁模式

这里我主要分析锁的模式。

记录锁

记录锁是最简单的行锁, 仅仅锁住一行 。即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁。(record lock)

间隙锁(Gap Locks)

间隙锁是一种加在两个索引之间的锁,或者加在第一个索引之前,或最后一个索引之后的间隙。主要对一个区间而加锁。关键字(gap before rec)

Next-Key Locks

Next-key锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录前面间隙上的锁。

插入意向锁(Insert Intention)

插入意向锁是在插入一行记录操作之前设置的一种间隙锁,这个锁释放了一种插入方式的信号。

锁模式兼容矩阵(横向是已持有锁,纵向是正在请求的锁):

在这里插入图片描述

2.实现死锁

实现死锁的步骤详细看下面的链接。

这里实现死锁之前的sql。

图片

3.如读死锁日志

使用 show engine innodb status 查看死锁日志。

如何实现死锁,详细可以看链接文章,由于时间关系借了其的死锁日志简单分析。

(“//”则是自己写的话)

2020-04-11 00:35:55 0x243c
*** (1) TRANSACTION: //表示第一个事务
TRANSACTION 38048, ACTIVE 92 sec inserting(2020-04-11 00:35:55 0x243c
*** (1) TRANSACTION:
TRANSACTION 38048, ACTIVE 92 sec inserting //这个事务执行插入sql
mysql tables in use 1, locked 1 //这个表存在锁
LOCK WAIT 4 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2  //正在等待锁
MySQL thread id 53, OS thread handle 2300, query id 2362 localhost ::1 root update
insert into account values(null,'Jay',100)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: //正在等待锁被释放
RECORD LOCKS space id 177 page no 4 n bits 80 index idx_name of table `test2`.`account` //希望锁的索引
trx id 38048 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 //这个比较重要大概意思是 准备插入但是正在等待获取获取意向插入锁
//下面则是表示 这个锁会锁的范围 
//重点留有这个范围 标记为 A
 0: len 3; hex 576569; asc Wei;;(不包含Wei)
 1: len 4; hex 80000002; asc     ;;(未知)
 
*** (2) TRANSACTION: //表示第二个事务
TRANSACTION 38049, ACTIVE 72 sec inserting, thread declared inside InnoDB 5000 //这个事务执行插入sql
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
MySQL thread id 52, OS thread handle 9276, query id 2363 localhost ::1 root update
insert into account  values(null,'Yan',100)
*** (2) HOLDS THE LOCK(S): //重要点 这个事务锁上了一个锁
RECORD LOCKS space id 177 page no 4 n bits 80 index idx_name of table `test2`.`account` //这个锁 锁的索引
trx id 38049 lock_mode X locks gap before rec //表示上了一个排他间隙锁
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
//这个锁 锁的索引的详细的节点范围
//重点留有这个范围 标记为 B ,可见和A的存在交集,则会冲突
 0: len 3; hex 576569; asc Wei;;(不包含Wei)
 1: len 4; hex 80000002; asc     ;;(未知)
 
*** (2) WAITING FOR THIS LOCK TO BE GRANTED: //同是第二个事务 等待锁
RECORD LOCKS space id 177 page no 4 n bits 80 index idx_name of table `test2`.`account`  //希望锁的索引
trx id 38049 lock_mode X insert intention waiting //等待插入意向锁
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
//等待的锁的索引范围 可见和A的存在交集,则会冲突
 0: len 8; hex 73757072656d756d; asc supremum;; (无限)

上面的日志可以简单分析:

事务B执行更新时候 会锁了部分节点的索引,然后 事务A 执行插入 数据的索引节点刚刚好和事务B的持有的索引锁冲突了,A则等待B释放,然后B又则行了insert的索引节点需要的锁和A希望持有的冲突的了。锁会排队,先申请先获取的,所以就会 A等B B等A的情况出现死锁。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMFwsfia-1611302392078)(https://uploader.shimo.im/f/9sVpaVEx230LVgfo.png!thumbnail?fileGuid=Gkkp99VTJxrVvhkt)]

我认为 可以先判断锁之间的互斥关系,然后互斥,则判断其锁的范围,如果还是冲突,则会死锁了。

4.死锁解决方法

出现死锁,一般都会设置超时的时间的,也可以通过命令是用来查看当前运行的所有事务:

SELECT * FROM information_schema.INNODB_TRX;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-szZw7yjB-1611302392081)(https://uploader.shimo.im/f/YK5VGYOZITiYiU2Q.png!thumbnail?fileGuid=Gkkp99VTJxrVvhkt)]

然后 killtrx_mysql_thread_id

再排除出现死锁的操作,从而优化代码架构。

5.避免方法

简单的建议:

高并发提前对操作同一个数据锁。

尽量减少大事务,执行时间尽量短。

感谢参考链接:

https://www.tuicool.com/articles/zEvU3me

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值