暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

Mysql_next-key与幻读

原创 何同学 2020-09-10
741

认识锁的算法

nnoDB存储引擎的锁的算法有三种:

Record lock:单个行记录上的锁
Gap lock:间隙锁,锁定一个范围,不包括记录本身
Next-key lock:record+gap 锁定一个范围,包含记录本身
Lock的精度(type)分为 行锁、表锁、意向锁

Lock的模式(mode)分为:

锁的类型 ——【读锁和写锁】或者【共享锁和排他锁】即 【X or S】
锁的范围 ——【record lock、gap lock、Next-key lock】

知识点

innodb对于行的查询使用next-key lock
Next-locking keying为了解决Phantom Problem幻读问题
当查询的索引含有唯一属性时,将next-key lock降级为record key
Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1

首先什么是幻读呢?

举个例子,两个男孩同时在追求一个女生的故事

A问:你有男朋友吗?女孩对他说没有。A追求女孩的事件还没有提交,就是继续追求哈。

就在A追求的同时,B也在追求,并且直接让女孩做他的女朋友,女孩答应了,B的追求事件结束。

A又问:你有男朋友吗? 女孩对他说我已经有男朋友了! 呜呜呜 !刚才你还没有的,怎么现在就有了呢?

女孩说,你也没说过你追我的时候不让别人追我啊!… … A哭着走了。

幻读 Phantom Problem 是指在同一事务下,连续执行两次相同的sql语句可能导致不同的结果,第二次的sql语句可能会返回之前不存在的行。

在刚才我举的例子里,A虽然问了女孩有没有男朋友,但是没有告诉女孩,在他追求时,不可以接受别人的追求,所以悲催的结局。

那么A怎么才能在他追求事件结束前让女孩不答应别人的追求呢?

innodb中的RR隔离级别是通过next-key locking是如何解决幻读问题的,就是锁住一个范围。

那么如果你是A你怎么做呢?你肯定要跟女孩说,只要我开始追求你,问了你有没有男朋友,在我结束追求你之前,你不可以答应别人的追求!我要把你脑子里记录男朋友的区域全部锁起来,啊哈啊!

下面我们来做一个测试,分别在RR和RC隔离级别中来实现:

测试使用表db1.t1 (a int primary key) ,记录有1,3,5

image.png

MariaDB [db1]> create table t1 (a int primary key);
Query OK, 0 rows affected (0.22 sec)

MariaDB [db1]> insert into t1 values (1),(3),(5);
Query OK, 3 rows affected (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 0

#事务T1
MariaDB [db1]> begin;
Query OK, 0 rows affected (0.00 sec)

MariaDB [db1]> set session transaction isolation level read co
Query OK, 0 rows affected (0.01 sec)

MariaDB [db1]> select * from db1.t1 where a>3 for update;
±–+
| a |
±–+
| 5 |
±–+
1 row in set (0.01 sec)

#事务T2
MariaDB [db1]> begin;
Query OK, 0 rows affected (0.00 sec)

MariaDB [db1]> insert into db1.t1 values (4);
Query OK, 1 row affected (0.00 sec)

MariaDB [db1]> commit;
Query OK, 0 rows affected (0.03 sec)

#事务T1
MariaDB [db1]> select * from db1.t1 where a>3 for update;
±–+
| a |
±–+
| 4 |
| 5 |
±–+
2 rows in set (0.00 sec)

将会话中的隔离界别改为RR,并删除a=4记录。

MariaDB [db1]> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

MariaDB [db1]> delete from db1.t1 where a=4;
Query OK, 1 row affected (0.00 sec)

image.png

#事务T1
MariaDB [(none)]> begin;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> select * from db1.t1 where a>3 for update;
±–+
| a |
±–+
| 5 |
±–+
1 row in set (0.02 sec)

#事务T2
MariaDB [(none)]> begin;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> insert into db1.t1 values (4);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
MariaDB [(none)]> commit;
Query OK, 0 rows affected (0.00 sec)

#事务T1
MariaDB [(none)]> select * from db1.t1 where a>3 for update;
±–+
| a |
±–+
| 5 |
±–+
1 row in set (0.02 sec)

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论