Skip to content

Commit

Permalink
fix image path
Browse files Browse the repository at this point in the history
  • Loading branch information
kinoxyz1 committed Nov 9, 2022
1 parent 3d64013 commit 60e8a3e
Showing 1 changed file with 13 additions and 13 deletions.
26 changes: 13 additions & 13 deletions note/MySQL/MYSQL锁.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@

在这种情况下会发生`脏写`的问题,任何一种隔离级别都不允许这种问题的发生。所以在多个未提交事务相继对一条记录做改动时,需要让它们`排队执行`,这个排队的过程其实是通过锁来实现的。这个所谓的锁其实是一个`内存中的结构`,在事务执行前本来是没有锁的,也就是说一开始是没有`锁结构`和记录进行关联的,如图所示:

![image-20220328182710276](../../img/mysql/mysql锁//image-20220328182710276.png)
![image-20220328182710276](../../img/mysql/mysql锁/image-20220328182710276.png)



当一个事务想对这条记录做改动时,首先会看看内存中有没有与这条记录关联的`锁结构`,当没有的时候就会在内存中生成一个`锁结构`与之关联。比如,事务`T1`要对这条记录做改动,就需要生成一个`锁结构`与之关联:

![image-20220328182721374](../../img/mysql/mysql锁//image-20220328182721374.png)
![image-20220328182721374](../../img/mysql/mysql锁/image-20220328182721374.png)



Expand All @@ -52,7 +52,7 @@



![image-20220328182808108](../../img/mysql/mysql锁//image-20220328182808108.png)
![image-20220328182808108](../../img/mysql/mysql锁/image-20220328182808108.png)

小结几种说法:

Expand Down Expand Up @@ -631,13 +631,13 @@ INSERT INTO student VALUES
记录锁也就是仅仅把一条记录锁上,官方的类型名称为:`LOCK_REC_NOT_GAP`。比如我们把id值为 8 的
那条记录加一个记录锁的示意图如图所示。仅仅是锁住了id值为 8 的记录,对周围的数据没有影响。

![image-20220328185943202](../../img/mysql/mysql锁//image-20220328185943202.png)
![image-20220328185943202](../../img/mysql/mysql锁/image-20220328185943202.png)



举例如下:

![image-20220328185953649](../../img/mysql/mysql锁//image-20220328185953649.png)
![image-20220328185953649](../../img/mysql/mysql锁/image-20220328185953649.png)

记录锁是有S锁和X锁之分的,称之为`S型记录锁``X型记录锁`

Expand All @@ -648,7 +648,7 @@ INSERT INTO student VALUES

MySQL在`REPEATABLE READ`隔离级别下是可以解决幻读问题的,解决方案有两种,可以使用`MVCC`方案解决,也可以采用加锁方案解决。但是在使用`加锁`方案解决时有个大问题,就是事务在第一次执行读取操作时,那些幻影记录尚不存在,我们无法给这些`幻影记录`加上`记录锁`。InnoDB提出了一种称之为`Gap Locks`的锁,官方的类型名称为:`LOCK_GAP`,我们可以简称为`gap锁`。比如,把id值为 8 的那条记录加一个gap锁的示意图如下。

![image-20220328190138150](../../img/mysql/mysql锁//image-20220328190138150.png)
![image-20220328190138150](../../img/mysql/mysql锁/image-20220328190138150.png)

图中id值为 8 的记录加了gap锁,意味着`不允许别的事务在id值为 8 的记录前边的间隙插入新记录`,其实就是id列的值( 3 , 8 )这个区间的新记录是不允许立即插入的。比如,有另外一个事务再想插入一条id值为 4 的新记录,它定位到该条新记录的下一条记录的id值为 8 ,而这条记录上又有一个gap锁,所以就会阻塞插入操作,直到拥有这个gap锁的事务提交了之后,id列的值在区间( 3 , 8 )中的新记录才可以被插入。

Expand Down Expand Up @@ -907,7 +907,7 @@ InnoDB内部就不会有大量的死锁检测工作了。

InnoDB存储引擎中的锁结构如下:

![image-20220328191907367](../../img/mysql/mysql锁//image-20220328191907367.png)
![image-20220328191907367](../../img/mysql/mysql锁/image-20220328191907367.png)



Expand Down Expand Up @@ -950,7 +950,7 @@ InnoDB存储引擎中的锁结构如下:

这是一个 32 位的数,被分成了lock_mode、lock_type和rec_lock_type三个部分,如图所示:

![image-20220328192308086](../../img/mysql/mysql锁//image-20220328192308086.png)
![image-20220328192308086](../../img/mysql/mysql锁/image-20220328192308086.png)



Expand Down Expand Up @@ -1184,7 +1184,7 @@ insert into test values( 0 , 0 , 0 ),( 5 , 5 , 5 ),

##### 案例一:唯一索引等值查询间隙锁

![image-20220328193145028](../../img/mysql/mysql锁//image-20220328193145028.png)
![image-20220328193145028](../../img/mysql/mysql锁/image-20220328193145028.png)

由于表 test 中没有 id=7 的记录

Expand Down Expand Up @@ -1304,7 +1304,7 @@ session A 是一个范围查询,按照原则 1 的话,应该是索引 id 上

由于c是普通索引,所以继续向右查找,直到碰到 (col1=15,id=15) 这一行循环才结束。根据优化 2 ,这是一个等值查询,向右查找到了不满足条件的行,所以会退化成 (col1=10,id=10) 到 (col1=15,id=15) 的间隙锁。

![image-20220328194408224](../../img/mysql/mysql锁//image-20220328194408224.png)
![image-20220328194408224](../../img/mysql/mysql锁/image-20220328194408224.png)



Expand All @@ -1329,7 +1329,7 @@ session A 的 delete 语句加了 limit 2 。你知道表 t 里 c=10 的记录
满足条件的语句已经有两条,循环就结束了。因此,索引 col1 上的加锁范围就变成了从( col1=5,id=5)
到( col1=10,id=30) 这个前开后闭区间,如下图所示:

![image-20220328194529282](../../img/mysql/mysql锁//image-20220328194529282.png)
![image-20220328194529282](../../img/mysql/mysql锁/image-20220328194529282.png)

这个例子对我们实践的指导意义就是, 在删除数据的时候尽量加 limit 。

Expand Down Expand Up @@ -1359,7 +1359,7 @@ select * from test where id>9 and id<12 order by id desc for update;

下图为这个表的索引id的示意图。

![image-20220328194721419](../../img/mysql/mysql锁//image-20220328194721419.png)
![image-20220328194721419](../../img/mysql/mysql锁/image-20220328194721419.png)

1. 首先这个查询语句的语义是 order by id desc ,要拿到满足条件的所有行,优化器必须先找到 “ 第一个 id<12 的值 ” 。
2. 这个过程是通过索引树的搜索过程得到的,在引擎内部,其实是要找到 id=12 的这个值,只是最终没找到,但找到了 (10,15) 这个间隙。( id=15 不满足条件,所以 next-key lock 退化为了间隙锁 (10,15) 。)
Expand Down Expand Up @@ -1406,7 +1406,7 @@ session A 的加锁范围是索引 col1 上的 (5,10] 、 (10,15] 、 (15,20]

通过这个操作, session A 的加锁范围变成了图 7 所示的样子:

![image-20220328194922739](../../img/mysql/mysql锁//image-20220328194922739.png)
![image-20220328194922739](../../img/mysql/mysql锁/image-20220328194922739.png)



Expand Down

0 comments on commit 60e8a3e

Please sign in to comment.