避免幻读 : next-key锁与MVCC

文章目录

  • ​​引言​​
  • ​​next-key锁​​
  • ​​多版本并发控制(MVCC)​​
  • ​​两者的区别​​
  • ​​总结​​

引言

在隔离级别为RR时,MySQL已经可以避免脏读和重复读,但还是无法避免幻读,MySQL采用next-key锁与MVCC(加锁多版本并发控制)来避免幻读.

nexmvc框架t-key锁

next-key 锁是索引 record 上的 rmysql密码忘记了怎么办ecord 锁和 index record 之前的间隙上的间隙锁的组合。
InnoDB以mysql数据库这样的方式执加锁速度行 row-level 锁定:当它搜索或扫描 table 索引时,它会在它遇到的索引记录mvc模式上设置共享锁或独占锁。因此,row-level 锁实际上是 index-reco数据库系统概论第五版课后答案rd 锁。索引 record 上的 next-key 锁也会影响索引 record 之前的“间隙”。也就是说,next-key 锁是 ind数据库ex-record 锁加上在 index record 之前的间隙上的mvc框架间隙锁。如果一个 sessio数据库查询语句n 在索引中mysql的 record R上有共享或独占锁定,则另一个 session 不能在_le之前的R之前的间隙中插入新的索引 record。

以上是文档中对于next_key的解释,相信第一遍看的时候一定是有点懵逼的,什么意思呢?mysql数据库基础知识

假设我们现在有一个表,数mvc模式据是这样的[(1,‘a’),(3,‘c’),(5,‘e’),(7,‘g’),(9,‘i’),(11,‘k’)],文档的意思是当我们在会话A中查询(9,‘i’)的时候,(7,9]是被锁定的,文档的意思是之前,但是经过测试其实前后两个区间,即(7,9],(9,11]都是锁定的,那么当我们锁定11的时候呢?(9,11](11,positive infinity数据库系统概论第五版课后答案]都是锁定的,下面是对这个例子的小实验.

执行下述语句

//会话1
mysql root@(none):test_mysql1> create table test_next_key
-> (id int primary key auto_increment,
-> name char(5) not NULL,
-> KEY `index_name` (name));
Query OK, 0 rows affected
Time: 0.030s
mysql root@(none):test_mysql1> insert into test_next_key values(1,'a'),(3,'c'),(5,'e'),(7,'g'),(9,'i'),(11,'k');
Query OK, 6 rows affected
Time: 0.005s
mysql root@(none):test_mysql1> start transaction;
//会话2
mysql root@(none):test_mysql1> start transaction;

mysql root@(none):test_mysql1> insert into test_next_key(id,name) values(2,'b');
Query OK, 1 row affected
Time: 0.001s
mysql root@(none):test_mysql1> insert into test_next_key(id,name) values(4,'d');
Query OK, 1 row affected
Time: 0.001s
mysql root@(none):test_mysql1> insert into test_next_key(id,name) values(6,'f');
Query OK, 1 row affected
Time: 0.001s

mysql root@(none):test_mysql1> insert into test_next_key(id,name) values(8,'h');
Ccancelled query //Ctrl+C
mysql root@(none):test_mysql1> insert into test_next_key(id,name) values(10,'j');
Ccancelled query

mysql root@(none):test_mysql1> insert into test_next_key(id,name) values(12,'l');
Query OK, 1 row affected
Time: 0.003s

mysql root@(none):test_mysql1> rollback ;
Query OK, 0 rows affected
Time: 0.000s
mysql root@(none):test_mysql1> select * from test_next_key
+----+------+
| id | name |
+----+------+
| 1 | a |
| 3 | c |
| 5 | e |
| 7 | g |
| 9 | i |
| 11 | k |
| 12 | l |(为什么回滚了还是进入数据库里了?)
+----+------+

根据会话2我们可以看到id为数据库系统概论8和10时是没有办法插入的,这也和上面所说的一致,因为(7,9],(9,11]这两个区间是被next_key锁定的,当然当我们查看的是12的时候,此时锁定的就是后面的的区间了.示例如下

//会话1
mysql root@(none):test_mysql1> start transaction;
Query OK, 0 rows affected
Time: 0.000s
mysql root@(none):test_mysql1> select * from test_next_key where name='k' for update;
+----+------+
| id | name |
+----+------+
| 11 | k |
+----+------+
1 row in set
Time: 0.004s
mysql root@(none):test_mysql1>
//会话2
mysql root@(none):test_mysql1> start transaction;
Query OK, 0 rows affected
Time: 0.000s
mysql root@(none):test_mysql1> insert into test_next_key(id,name) values(12,'l');
(1205, 'Lock wait timeout exceeded; try restarting transaction')

那么next-key锁是如何避免幻读的呢,我们不妨先想想什么时候可能出现幻读?
即插入到我们查询范围内的空隙中的时候.举个例数据库系统工程师子,假设我们有一查询语句SELECT * FROM child WHERE id > 100,此时如果另一个事务向100之后插入一条记录的话,加锁速度此事务再select就会出现幻读了.再比如​SELECT * FROM child WHERE id BEmysql安装TWEEN 80 AND 100​,数据库此时如果向[80,100]之间加锁插入数据就会出现幻读.

To prevent phantoms, InnoDB uses an algorithm called加锁的备忘录忘记密码 next-key locking that combines index-row locking with gap lockimvc框架ng. InnoDB performs row-level locking in such a way that whe加锁速度n it searchemysql安装s or scans a table index, it setmvcc实现原理s shared or exclusive locks on the index records it encounters. Thus, the row-level locks are actually index-record locks. In addition, a next-key lock on an index record also affects the “gap” before that index record. That is, a next-key lock is an index-record lock plus a gap lock on the gap premysql怎么读ceding the index record. If one session has加锁 a sha加锁red or exclusive lock on record R in an index, another session cann加锁速度ot insert a new index record in the gap immediatel加锁速度y before R in the index order.

为了防止幻像,InnoDB使用一种名为 next-kemvc和mvvm区别y 锁定的算法,该算法将 index-row 锁定与间隙锁定相结合。 InnoDB以这样的方式执行 row-level 锁定:当它搜索或扫描mvc三层架构 table 索引时,它会在它遇到的索引记录上设置共享锁或独占锁mvc和mvvm区别。因此,row-level 锁实际上是 index-record 锁。另外,索引 record 上的 next-key 锁也会影响索引 record 之前的“间隙”。也就是说,next-key 锁是一个 index-record 锁加上在 imvc框架ndeMVCx record 之前的间隙上的间隙锁。如果一个 session 在索引中的 recormysql数据库命令大全d R上有共享或独占锁定,则另一个 session 不能在R之前的R之前的间隙中插入新的索引数据库系统概论第五版课后答案 record。

文档中不但解释清楚了如何mysql基础命令避免幻读,还对next_key下了一个定义,即​​next-key 锁是一个 index-recomvc华信rd 锁加上在 index数据库系统工程师 record 之前的间隙上的间隙锁.​

这里出现幻读的条件无非有三种,next_kemysql安装配置教程y锁都可以很好的解决幻读

  • where id > n; 会在实际mysql面试题存在的最后一个值上加(N_max, positive infinitymysql数据库)这个gap锁 其他的值加next_key锁
  • BETWEEN lhs AND rhs; 在扫描每一个值时对其加index-record 锁,然后在对这个index的前面的间隙加gap锁
  • where id < n; 会在实际存在的最小值上加 (negativemvcat infinity, N_min],其他的值加next_key锁

mvc三层架构版本并发控制(MVCC)

其实MVCC本来的用途是解决写时加锁不能读的问题,也就是增加读的速度,可以代替行锁.说实话,这玩意确实很像乐观锁,它们的关系我现在还mysql安装配置教程太才疏学浅,没办法理清楚,​​可参考这篇博客​​​.但其确实可以解决幻读,加锁的备忘录忘记密码MVCC逻辑比较简单,基本内容可参考这篇博客.

两者的区别

既然都可以避免幻读,那么它们有什么区别呢?

答案就是,​在快照读时使用MVCCmvc设计模式,在当前读时使用next_key锁​.

那么什么是快照读,什么又数据库是当前读呢?

  • 快照读:读取的是记录的可见版本(有可能是历史版本),不加锁。
    场景:select
  • 当前读:读取的是记录的最新版本,并且当前读返回的记录会加锁,保证其他事务不会再并发修改这mysql安装配置教程条记录。
    场景:update、insert、delete

其实也很好想,当我们select的时候,因为MVCC的特性使得我们根本不需要锁,因为MVCC所加的记录删除时间的列会帮我们筛选掉幻读的行,从而在不加锁的情况下避免幻读.但是此时数据仍mvc模式然是可以加入表的数据库系统概论.但是当我们需要对表进行修改的时候就不一样了,此时MVCC显然无法满足要求,我们需要保证在一个区间插入的时候其他会话不在此区间进行插入,所采取的策略就是next_key锁,关于nextmysql数据库_key锁,上面讲的很清楚了.

总结

一个小小的知识点却能牵引出这么多东西,平时忽略的数据库管理系统小知识点不知道让我们遗漏了多少本该掌握的东西,还是要始终保持着一颗好奇与敬畏之心才可.

参考
​​​https://dev.mysql.co数据库管理系统m/doc/refman/5.6/en/innodb-locking.html#innodb-nemvc框架xt-key-locks​​

​​https://dev数据库系统概论.mysql.com/doc/refman/5.6/enMVC/数据库系统工程师innodb-next-key-locking.html​​

​​https://www.docs4dev.com/docs/zh/mysql/5.7/reference/innodb-next-key-locking.html​​

MySQL之Innodb数据库原理锁机制:Next-Key Lock 浅谈 ps:详尽的测试

innodmvc模式b锁-next-key锁 ps:简单的测试

快照读,当前读

InnoDB的MVCC如何解决不可重复读和快照读的幻读mysql安装配置教程,当前读用next-key解决幻读

聊聊MVCMVCC和Next-key Locks