2 s锁是什么_事务的隔离级别与锁实践(二)

  1.InnoDB 存储引擎下的锁    1.1 锁分类  1.2 Shared and Exclusive Locks 共享锁 与 排他锁            1.2.1多个事务对 S 锁持有处理            1.2.2多个事务对 X 锁持有处理

       1.3 Intention Locks 意向锁

       1.4 Record Locks 记录锁

       1.5 Gap Locks 间隙锁

       1.6 Next-Key Locks

       1.7 Insert Intention Locks 插入意向锁

       1.8 AUTO_INC Locks 自增锁  

       1.9 Predicate Locks for Spatial Indexes

接前文(见 事务的隔离级别与锁实践),继续说明 MySQL 在 RR 级别下如何解决不可重复读及幻读问题。

1. InnoDB 存储引擎下的锁

在解释上述问题前,我们先了解 InnoDB 引擎下锁的基础知识。

1.1 锁分类

在 InnoDB 引擎下,有多种类型的锁:

•Shared and Exclusive Locks
共享锁 与 排他锁,行级别锁•Intention Locks
意向锁,表级别锁•Record Locks
记录锁•Gap Locks
间隙锁•Next-Key Locks
记录锁 与 间隙锁的结合•Insert Intention Locks
插入意向锁•AUTO-INC Locks
自增锁•Predicate Locks for Spatial Indexes
空间索引谓词锁

下面将逐一介绍:

1.2 Shared and Exclusive Locks 共享锁 与 排他锁

共享锁 与 排他锁,是 InnoDB 实现的两种「行级别锁」(row-level locking):

•共享锁
简称为 S 锁,一个事务对一行数据持有 S 锁,则可以对该行进行「读」操作,又称之为「读锁」。•排他锁
简称为 X 锁,一个事务对一行数据持有 X 锁,则可以对该行进行「更新」或「删除」操作,又称之为「写锁」。

1.2.1 多个事务对 S 锁持有处理

如果事务 T1 对行数据 r 持有「读锁」(S 锁),另一事务 T2 对行数据 r 的锁申请处理如下:

•T2 即刻就可以获得 S 锁。即:T2 和 T1 对 r 都拥有「读锁」;•T2 不能立刻就获得 X 锁。

也就是说,当一个事务 T1 对一行数据 r 拥有 S 锁时,其他事务也可以正常读取该数据,但是不能在事务 T1 释放 S 锁之前,对其做更改操作。

1.2.2 多个事务对 X 锁持有处理

如果事务 T1 对行数据 r 持有「写锁」(X 锁),那么对于事务 T2 来说,既不能获取到 r 上的 S 锁,也不能获取到 r 上的 X 锁。T2 只能等 T1 去释放对 r 持有的锁。

总结,S 锁(读锁)是共享的,X 锁(写锁)是排他的

1.3 Intention Locks 意向锁

意向锁,「表级别锁」(table-level locking);

InnoDB 支持多粒度的锁,可以使行锁表锁共存。

例如:语句 LOCK TABLES t WRITE 在指定的表 t 上获取了排他锁(X 锁)。为了使锁在多个粒度更加实用,InnoDB 使用了意向锁。  

意向锁属于表级别的锁,意向锁暗示了一个事务 即将 在一张表的行数据上 要获取 何种类型 的锁。有两种类型的意向锁:

•意向共享锁(intention shared lock,IS 锁)
一个事务可能有意向对表中的部分行数加共享锁。例如:
语句 SELECT ... FOR SHARE 加 IS 锁。•意向排他锁(intention exclusive lock,IX 锁)
一个事务可能有意向对表中的部分行数据加排他锁。例如:
语句 SELECT ... FOR UPDATE 加 IX 锁。

意向锁协议如下:

•在一个事务获得表中一行数据共享锁之前,它一定必须先获得表中的意向共享锁(IS)。•在一个事务获得表中一行数据的排他锁之前,它一定必须先获得表中的意向排他锁(IX)

表级别锁的兼容性汇总如下:

XIXSIS
X冲突冲突冲突冲突
IX冲突兼容冲突兼容
S冲突冲突兼容兼容
IS冲突兼容兼容兼容

一个事务要获得的锁 L1,如果与已经存在的锁 L2 是兼容的,那么它将获得锁 L1;如果 L1 与 L2 是互斥冲突的,则它无法获得锁 L1。它只能一直等待,直到冲突的锁 L2 被释放掉。如果造成死锁(deadlock),将会出现错误。

意向锁不会阻塞任何事情,除非类似 LOCK TABLES ... WRITE 这样的全表请求。意向锁的主要目的是表明有事务 正在锁 表中的行 或者 即将去锁 表中的行。

1.4 Record Locks 记录锁

记录锁,也称为行锁。是在索引记录上的锁。

例如:SELECT c1 FROM t where c1 = 10 FOR UPDATE,会阻止任何其他事务对表 t 中满足 c1=10 的行数据进行添加更新或者删除

记录锁总是会锁住对应的索引记录,即使表中没有定义任何索引。这种情况下,InnoDB 会创建一个隐藏的聚集索引(clustered index),并且用这个索引去锁对应的记录。

注:聚集索引和第二索引,后续文章会继续解读

1.5 Gap Locks 间隙锁

间隙锁,是在索引记录之间的锁,主要作用是锁住某个范围(间隙)内的数据,从而保证此范围内的数据不会被修改更新。

例如:SELECT c1 FROM t WHERE c1 BETWEEN 10 AND 20 FOR UPDATE,如果有事务要插入的数据 c1 = 15,则不允许被插入,因为 10 到 15 这个范围间隙(gap)已经被间隙锁锁住了,不管 c1 = 15 在原有的数据中是否存在

一个间隙(gap)的范围可以是单个索引的值,或者是联合索引的值,甚至可以是空值。

间隙锁是在性能并发性之间做出的权衡,适用于 RR(Repeatable reads 可重复读)、Serializable(串行化)事务隔离级别。

如果查询的条件是唯一索引,此时,间隙锁是无用的(因为查询到唯一行了,没有所谓的间隙),但是不包括联合唯一索引(多个列组成的唯一索引)这种情况,如果在查询条件是联合唯一索引的情况下,还是会用到间隙锁的。例如,如果 id 列有唯一的索引,语句:

SELECT * FROM child WHERE id = 100

会查出一行数据,即:id = 100 ,这行数据的锁就不是间隙锁(gap locks)了,而是索引记录锁(index-record lock),其他事务无论如何插入数据都无所谓了。如果 id 没有被索引 或者是 非唯一索引,仍会有间隙锁。

在 RC(Read committed 读已提交)隔离级别下,不会存在间隙锁;

1.6 Next-Key Locks

Next-Key 锁是记录锁(Record Locks) 与 间隙锁(Gap Locks) 的结合。注意:一个间隙锁指的是对一个范围上的锁,而 Next-Key 锁则相当于是包含多个记录锁多个间隙锁,即 Next-Key 可能锁住了 多个索引记录 和 多个范围。假设有目前有如下表:

CREATE TABLE `t` (  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,  `cid` int(11) NOT NULL,  PRIMARY KEY (`id`),  KEY `Cid-Index` (`cid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

有如下数据:

idcid
23
68
810
914

此时如果有语句如:

select * from t where cid=8 for update;

则对应的 Next-Key 锁如下:

0a58eccbc49b9a5b8a273fca2dfe8aa0.png

其中,cid 列是普通索引,当查询条件是 cid=8 时,它被包含在 cid=3 和 cid=10 的数据范围内,则对应的两个间隙锁为:(3, 8) & (8, 10),且 cid=8 为记录锁cid=10 行数据由于不满足查询条件(cid=8),所以退化为间隙锁。故此例中的 Next-key Lock 中包含两个间隙锁 和 一个记录锁

假设一索引的包含了 10、11、13 和 20 这些值,那么可能的 Next-Key 锁(包括记录锁、间隙锁)的间隔区间如下:

(-∞, 10] 

(10, 11] 

(11, 13] 

(13, 20] 

(20, +∞)

InnoDB 正是通过 Next-Key 锁去解决幻读问题。

1.7 Insert Intention Locks 插入意向锁

插入意向锁,是一种特殊的 间隙锁,在 插入一行数据之前由 INSERT 操作产生。在同一个间隙范围内,如果多个事务要插入数据位置不一样,那么这些事务是不需要互相等待的。

假设有索引数据 4 和 7,两个不同的事务分别要插入数据 5 和 6,这两个事务在获取插入行的排他锁之前,都会使用插入意向锁去锁住 4 和 7 之间的间隙(gap),但这两个事务不会因此而相互阻塞(block),因为它们要插入的行是没有冲突的。

1.8 AUTO_INC Locks 自增锁

自增锁,一种特殊的 表级别 锁,当一个事务要插入数据列是 自增(AUTO_INCREMENT)时,保持连续自增的一种锁。

最简单的例子,如果一个事务 T1 正在插入数据,那么其他的事务也要插入数据,那么必须等待 T1,这样才能保证 T1 插入的主键 key 是连续的。

1.9 Predicate Locks for Spatial Indexes

空间谓词锁。

MySQL 对包含空间的列,支持空间索引。

注:空间可以由一个坐标点、坐标点组成的一条线或者不规则的多边形等组成的

处理包含空间索引的锁,next-key 锁在 RR(Repeatable reads 可重复读)、Serializable(串行化)事务隔离级别中并不能很好的支持,因为在空间的多维数据中,没有明确的排序概念,所以并不知道哪个是 next key

为了支持具有空间索引的表的隔离级别,InnoDB 使用了谓词锁(Predicate Locks)。一个空间索引包含了 MBR(minimum bounding rectangle,最小边界矩形)值,因而 InnoDB 在用于查询 MBR的值上设置谓词锁来强制对索引的一致性读取。其他事务对将要匹配的行,不能进行插入或者修改。

MySQL 基本锁的基础知识介绍完了,我们知道 MySQL InnoDB 是一个多版本的存储引擎,由于时间关系,下期我们着重介绍 MVCC(multiversion concurrency control,多版本并发控制)在 InnoDB 中的应用,及 RR 级别下怎么解决不可重复读以及幻读问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值