阅读innodb可重复读隔离级别下加锁的文档

This commit is contained in:
asahi
2024-11-17 22:39:41 +08:00
parent 698530d66a
commit 6f56194fb5

View File

@@ -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|