不是?我的行锁怎么就变成表锁了?
我的行锁在我不知情的情况下升级成了表锁
行锁和表锁
大家都知道,MySQL的InnoDB存储引擎支持事务,支持行级锁,那么大家有没有想过到底怎么实现这个行级锁呢?先埋个伏笔,往下看
那为什么要用行锁不用表锁,这个大家都懂,就是为了防止有并发的时候性能低这种情况嘛
所以如果在你什么都不知道的情况下,行锁自动升级成了表锁还是一件不好的事情的
索引分类
列举一下常见的索引:聚簇索引(主键索引)、唯一索引、普通索引、联合索引
- 主键索引:自带最高效率的索引
- 唯一索引:指该属性值重复率为0
- 普通索引:指该属性值重复率 > 0
行锁升级为表锁的场景
- 在不使用索引的情况下加锁,导致行锁升级为表锁
事务顺序 | 事务A | 事务B |
---|---|---|
1⃣️ | begin; | |
2⃣️ | select * from user where age = 20 for update; | |
3⃣️ | begin; | |
4⃣️ | select * from user where age = 19 for update; | |
5⃣️ | commit; | 这个时候事务B才能拿到锁 |
6⃣️ | commit; |
大家觉得在事务A提交之前,事务B能不能查得到?查询是不会加锁的,但是我们强制加锁为了方便测试而已
首先表中有两条数据
这个时候就有点纳闷了,我只是想差一条age=20的这一条数据,怎么就锁了整张表了呢?
可以从这个角度去思考,首先age字段是没有索引的,那数据库想要找到这条数据是不是要全表遍历?而且age字段加不了唯一索引
- 使用普通索引的情况进行加锁
对age字段添加了普通索引
alter table test_user add index idx_age(age);
事务顺序 | 事务A | 事务B |
---|---|---|
1⃣️ | begin; | |
2⃣️ | select * from user where age = 20 for update; | |
3⃣️ | begin; | |
4⃣️ | select * from user where age = 19 for update; | |
5⃣️ | commit; | commit |
可以发现在加了索引的情况下,行锁 是不会升级成表锁的
行锁是怎么加上去的?
还记得索引的B+树结构长什么样吗?
其实InnoDB的行锁就是通过给索引项进行加锁实现的
转载自:https://juejin.cn/post/7351320581684133923