From 6f56194fb52dbb0bd4d5022789fdfbcecb4db0cd Mon Sep 17 00:00:00 2001 From: asahi Date: Sun, 17 Nov 2024 22:39:41 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=85=E8=AF=BBinnodb=E5=8F=AF=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E8=AF=BB=E9=9A=94=E7=A6=BB=E7=BA=A7=E5=88=AB=E4=B8=8B?= =?UTF-8?q?=E5=8A=A0=E9=94=81=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/mysql文档/锁.md | 47 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/mysql/mysql文档/锁.md b/mysql/mysql文档/锁.md index 4df257f..799dbaf 100644 --- a/mysql/mysql文档/锁.md +++ b/mysql/mysql文档/锁.md @@ -211,7 +211,7 @@ insert into t_lear_lock(id, content, lv) values > - X: next_key_locking,`代表x和x之前的间隙` > - X,GAP:间隙锁,`代表x之前的间隙,不包含x记录本身` > - X, REC_NOT_GAP:`代表X记录本身,不包含之前的间隙` -> - X,GAP,INSERT_INTENTION:插入意向锁,彼此之前不互斥 +> - X,GAP,INSERT_INTENTION:插入意向锁,彼此之间不互斥 #### select ... 加锁情况 在开启事务后,执行`select * from t_lear_lock`语句,默认`并不会为index record或表加上任何锁`,在可重复读的隔离级别下,默认会采用无锁的一致性读方式,来读取数据的历史版本快照,期间并不需要进行任何加锁操作。 @@ -233,7 +233,11 @@ insert into t_lear_lock(id, content, lv) values |PRIMARY|RECORD|X|GRANTED|3| |PRIMARY|RECORD|X|GRANTED|4| -其中,`select * from t_learn_lock where content < 'h' and content > 'e' for update for update;`会查询出id为`3`的记录,但是由于未命中索引,`该语句会针对主键中所有的index record进行加锁`(包括 supremum prseudo-record)。 +其中,`select * from t_learn_lock where content < 'h' and content > 'e' for update for update;`会查询出id为`3`的记录,但是由于未命中索引,`该语句会针对主键中所有的index record进行加锁(包括 supremum prseudo-record)`。 + +并且,在可重复读(repeatable read)的隔离级别下,会针对所有的记录添加`next-key`锁,锁住index record和位于该记录之前的间隙。 + +而在读已提交(read committed)的隔离级别下,则只会针对index record来进行加锁,并不会添加间隙锁。 > ##### supremum preseudo-record > 该index record并不是一条真实存在的索引记录,其代表了`比索引中所有记录的值都大的一条虚拟记录`,类似有序链表中的尾节点。 @@ -251,12 +255,18 @@ insert into t_lear_lock(id, content, lv) values |PRIMARY|RECORD|X,REC_NOT_GAP|GRANTED|2| 上述查询语句会命中`(2, 'd', 7)`这条记录,但是,其针对索引加锁的操作如下: -- 对于`idx_lv`索引记录,不仅对语句查询出的`(7,2)`这条索引记录进行了加锁,还针对了下一条索引记录`(9,3)`进行了加锁 +- 对于`idx_lv`索引记录,不仅对语句查询出的`(7,2)`这条索引记录加了`next-key`锁,还针对了下一条索引记录`(9,3)`加了`next-key`锁 - 对于`primary`主键索引记录,则只针对查询出的id为2的记录进行了加锁`(2)` -对于`idx_lv`中`(9,3)`这条记录进行加锁,主要是为了防止幻读,当对`(9, 3)`这条记录加锁后,如果后续其他事务想要向lv值为`(7,9)`的范围内进行加锁时,需要获取 +对于`idx_lv`中`(9,3)`这条记录进行加锁,主要是为了防止幻读,当对`(9, 3)`这条记录加锁后,如果后续其他事务想要向lv值为`(7,9)`的范围内进行加锁时,会被间隙锁阻塞,故而保证多次读取结果都一致。 +##### select语句命中主键索引 +当unique命中主键索引时,则是会针对主键的index record添加记录锁(非间隙锁),示例如下`select * from t_learn_lock where id = 3 for update`,其加锁状况如下: +|ENGINE_TRANSACTION_ID|LOCK_TYPE|LOCK_MODE|LOCK_STATUS|LOCK_DATA| +|---------------------|---------|---------|-----------|---------| +|4381865|TABLE|IX|GRANTED|| +|4381865|RECORD|X,REC_NOT_GAP|GRANTED|3| #### update ... 加锁情况 @@ -274,6 +284,35 @@ insert into t_lear_lock(id, content, lv) values |PRIMARY|RECORD|X|GRANTED|3| |PRIMARY|RECORD|X|GRANTED|4| +##### update语句命中非unique索引 +类似于`select ... for update`命中非unique索引一样,update语句在命中非unique索引之后,`也会同时针对命中索引和主键索引进行加锁`。 + +例如,在`update t_learn_lock set content = 'fuck' where lv between 4 and 8;`该更新语句命中`idx_lv`索引之后,既针对`idx_lv`索引进行了加锁,又针对`primary`主键索引进行了加锁。 + +同样和select相似的是,该update语句只会修改`(2, 'd', 7)`记录,但是update语句仍然获取了`(3, 'f', 9)`记录的锁。 + +update语句获取锁的情况如下: + +|INDEX_NAME|LOCK_TYPE|LOCK_MODE|LOCK_STATUS|LOCK_DATA| +|----------|---------|---------|-----------|---------| +||TABLE|IX|GRANTED|| +|idx_lv|RECORD|X|GRANTED|7, 2| +|idx_lv|RECORD|X|GRANTED|9, 3| +|PRIMARY|RECORD|X,REC_NOT_GAP|GRANTED|3| +|PRIMARY|RECORD|X,REC_NOT_GAP|GRANTED|2| + +类似`select ... for update`,update语句针对非unique索引进行了`next-key`加锁。 + +##### update语句命中主键索引 +如果`update ...`语句命中主键索引,那么类似select语句,也同样只会针对索引记录添加记录所(非间隙) + +`update t_learn_lock set content = 'fuck' where id= 3;`语句加锁情况如下: + +|INDEX_NAME|LOCK_TYPE|LOCK_MODE|LOCK_STATUS|LOCK_DATA| +|----------|---------|---------|-----------|---------| +||TABLE|IX|GRANTED|| +|PRIMARY|RECORD|X,REC_NOT_GAP|GRANTED|3| +