InnoDB中的锁

欢迎访问原文地址来阅读最新版本
转载请注明出处:http://kang.fun/innodb-lock

一、锁的类型

Mysql可以按照粒度划分为表锁行锁

  • 表锁范围大,上锁慢,并发低
  • 行锁仅锁索引,上锁慢,并发高

InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。

而行锁又分为排他锁共享锁

  • 共享锁(S):允许获得该锁的事务读取数据行(读锁),同时允许其他事务获得该数据行上的共享锁,并且阻止其他事务获得数据行上的排他锁。
  • 排他锁(X):允许获得该锁的事务更新或删除数据行(写锁),同时阻止其他事务取得该数据行上的共享锁和排他锁。

表锁和行锁同时存在就会带来一个问题,如果要申请表锁的时候如何确定当前表没有行锁呢?简单的方式当然是遍历查找,但这样效率太低,所以引入了“意向锁”(intention lock)。在添加行锁之前对表添加意向锁。

slideshare上对意向锁的一段表述:

IS and IX locks allow access by multiple clients. They won’t necessarily conflict until they try to get real locks on the same rows.
But a table lock (ALTER TABLE, DROP TABLE, LOCK TABLES) blocks both IS and IX, and vice-versa.

翻译成中文:

IX(意向排他锁),IS(意向共享锁)是表级锁,不会和行级的X,S锁发生冲突。只会和表级的X,S发生冲突

除了上面提到的锁,还有一种,叫“间隙锁”。

二、InnoDB解决幻读的方式 - 间隙锁(Gap Locks)

什么是间隙锁呢?先来看看Mysql官网上的定义:

A gap lock is a lock on a gap between index records, or a lock on the gap before the first or after the last index record.

翻译过来就是:间隙锁(Gap Lock)锁定的是索引记录之间的间隙、第一个索引之前的间隙或者最后一个索引之后的间隙

比如,当前数据库存在这样的一张person表,id是主键,age是普通索引,即二级索引:

idnameage
1张三13
3李四14
4王五16

在事务A中有一项操作是查询id在1~3范围内的数据:

...
select * from person where id between 1 and 3
...

显而易见,应该返回张三李四这两条数据。

但如果在事务A尚未提交时,此时另一个事务B插入一条id为2的数据,并提交成功,那么当事务A结束后,会发现查询出来的数据(2条)少于数据库当前存在的数据数量(3条),这就产生了幻读的问题。

所以InnoDB引入间隙锁,来锁住1到3中所有的数据,这样不会有其他事务影响当前事务的范围操作。

这就是间隙锁的主要、唯一目的:阻止其他事务在间隙上插入记录

为什么要锁住“第一个索引之前的间隙或者最后一个索引之后的间隙”呢?

再举个例子:

select * from person where age = '14' for update

这时如果另一个事务执行如下操作,会发现执行失败:

insert into person values(2, '赵六', 14)

这就引出另一个问题:数据间隙的分析时,优先通过二级索引排序,再通过二级索引中存储的主键排序

由于二级索引存放在B+树上,B+树的特点是不允许值重复,所以需要让主键共同参与二级索引值的构成来保证唯一性。

二级索引指向主键而不是数据地址,这样防止行移动或者数据页分裂时导致的二级索引维护工作。

所以,你的期望是锁住age为14的数据,但数据库不知道你要锁住的是14和哪个主键构成的二级索引,所以只能把id在1~3范围内的数据都锁住。

另外其间隙锁的区间是(1, 3],即大于1小于等于3。

Next-key 锁

相当于一个索引记录锁加上该记录之前的一个间隙锁。

三、Mysql数据上锁方式

1. 被动锁

对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁

2. 主动锁

  • FOR UPDATE

    增加排他锁

  • FOR SHARE

    增加共享锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值