简单了解 MySQL 中相关的锁

本文主要是带大家快速了解 InnoDB 中锁相关的知识

为什么需要加锁

首先,为什么要加锁?我想我不用多说了,想象接下来的场景你就能 GET 了。

你在商场的卫生间上厕所,此时你一定会做的操作是啥?锁门。如果不锁门,上厕所上着上着,啪一下门就被打开了,可能大概也许似乎貌似有那么一丁点的不太合适。

数据也是一样,在并发的场景下,如果不对数据加锁,会直接破坏数据的一致性,并且如果你的业务涉及到钱,那后果就更严重了。

锁门表情包

锁的分类

在 InnoDB 中,都有哪些锁?其实你应该已经知道了很多了,例如面试中会问你存储引擎 MyISAM 和 InnoDB 的区别,你会说 MyIASM 只有表锁,但是 InnoDB 同时支持行锁和表锁。你可能还会被问到乐观锁和悲观锁的区别是啥。

锁的概念、名词很多,如果你没有对锁构建出一个完整的世界观,那么你理解起来就会比较有阻碍,接下来我们把这些锁给分一下类。

按照锁的粒度

按照锁的粒度进行划分可以分为:

表锁

行锁

这里就不讨论页锁了,页锁是 BDB(BerkeleyDB) 存储引擎中才有的概念,我们这里主要讨论 InnoDB 存储引擎。

按照锁的思想

按照加锁的思想可以分为:

悲观锁

乐观锁

这里的悲观、乐观和你平时理解的名词是同一个意思。乐观锁认为大概率不会发生冲突,只在必要的时候加锁。而悲观锁认为大概率会冲突,所以无论是否必要加锁都会执行加锁操作。

按照兼容性

按照兼容性可以把锁划分为:

共享锁

排他锁

被加上共享锁的资源,能够和其他人进行共享,而如果被加上了排他锁,其他人在拿不到这把锁的情况下是无法进行任何操作的。

按照锁的实现

这里的实现就是 InnoDB 中具体的锁的种类了,分别有:

意向锁(Intention Locks)

记录锁(Record Locks)

间隙锁(Gap Locks)

临键锁(Next-Key Locks)

插入意向锁(Insert Intention Locks)

自增锁(AUTO-INC Locks)

即使按照这种分类来对锁进行了划分,看到了这么多的锁的名词可能仍然会有点懵。比如我SELECT ... FOR UPDATE 的时候到底加的是什么锁?

我们应该透过现象看本质,本质是什么?本质是锁到底加在了什么对象上,而这个很好回答:

加在了表上

加在了行上

而对于加在行上的锁,其本质又是什么?本质是将锁加在了索引上。

意向锁

在 InnoDB 中支持了不同粒度的锁,行锁和表锁。例如lock tables命令就会持有对应表的排他锁。为了使多种不同粒度的锁更实用,InnoDB 设计了意向锁

意向锁是一种表级锁,它表明了接下来的事务中,会使用哪种类型的锁,它有以下两种类型:

共享意向锁(IS) 表明该事务会打算对表中的记录加共享锁

独占意向锁(IX) 则是加排他锁

例如,select ... for share就是加的共享意向锁,而SELECT .. FOR UPDATE则是加的独占意向锁。其规则如下:

一个事务如果想要获取某张表中某行的共享锁,它必须先获取该表的共享意向锁,或者独占意向锁。

同理,如果想获取排他锁,它必须先获取独占意向锁

下图是这几种锁的组合下相互互斥、兼容的情况

简单了解 MySQL 中相关的锁

对照上面的表,在相互兼容的情况下,对应的事务就能获取锁,但是如果不兼容则无法获取锁,直到不兼容的锁释放之后才能获取。

看到这里你可能就会有问题了,那既然意向锁除了 LOCK TBALES 之外什么都不阻塞。那我要它何用?

还是通过例子,假设事务 A 获取了 student 表中 id = 100 这行的共享锁,之后事务 B 需要申请 student 表的排他锁。而这两把锁明显是冲突的,而且还是对于同一行。

那 InnoDB 需要如何感知 A 获取了这把锁?遍历整个 B+ 树吗?不,答案就是意向锁。事务 B 申请写表的排他锁时,InnoDB 会发现事务 A 已经获取了该表的意向共享锁,说明 student 表中已经有记录被共享锁锁住了。此时就会阻塞住。

并且,意向锁除了像LOCK TABLES这种操作之外,不会阻塞其他任何操作。换句话说,意向锁只会和表级别的锁之间发生冲突,而不会和行级锁发生冲突。因为意向锁的主要目的是为了表明有人即将、或者正在锁定某一行。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpwzx.html