Next-Key Locks

A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index 

record. 

是一个记录锁在索引记录上和一个区间锁在区间的组合 在index record之前

InnoDB 执行行级锁以这种方式 当它搜索或者扫描一个表的索引,它设置共享或者排它锁在Index records。

因此, row-level locks 实际上是 index-record locks.

一个 next-key lock 在一个index record 也会影响 那个index record 记录前的gap

也就是说 一个next-key lock 是一个 index-record lock plus a gap lock 

If one session has a shared or exclusive lock on record R in an index, another session cannot insert a new index 

record in the gap immediately before R in the index order. 

如果一个session 有一个共享或者排它锁在记录R上,另外的session 不能插入新的index record 在before R这个区间

Session 1:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> update SmsTest set phoneNo=111 where phoneNo <10;
Query OK, 20 rows affected (0.01 sec)
Rows matched: 20 Changed: 20 Warnings: 0 mysql> explain update SmsTest set phoneNo=111 where phoneNo <10;
+----+-------------+---------+-------+---------------+--------------+---------+-------+------ +------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+--------------+---------+-------+------ +------------------------------+
| 1 | SIMPLE | SmsTest | range | SmsTest_idx1 | SmsTest_idx1 | 4 | const | 20 | Using where; Using temporary |
+----+-------------+---------+-------+---------------+--------------+---------+-------+------ +------------------------------+
1 row in set (0.00 sec) 锁住1-9的记录 mysql> select * from SmsTest where phoneNo <10;
+-------+---------+-------------+--------+
| sn | phoneNo | channelType | status |
+-------+---------+-------------+--------+
| 1 | 1 | 2 | 1 |
| 45210 | 1 | 1 | 1 |
| 45211 | 1 | 1 | 1 |
| 2 | 2 | 2 | 1 |
| 201 | 2 | 1 | 1 |
| 45212 | 2 | 1 | 1 |
| 3 | 3 | 2 | 1 |
| 45209 | 3 | 1 | 1 |
| 45213 | 3 | 1 | 1 |
| 4 | 4 | 2 | 1 |
| 45214 | 4 | 1 | 1 |
| 5 | 5 | 2 | 1 |
| 45215 | 5 | 1 | 1 |
| 6 | 6 | 2 | 1 |
| 45216 | 6 | 1 | 1 |
| 7 | 7 | 2 | 1 |
| 45217 | 7 | 1 | 1 |
| 8 | 8 | 2 | 1 |
| 45218 | 8 | 1 | 1 |
| 9 | 9 | 2 | 1 |
+-------+---------+-------------+--------+
20 rows in set (0.00 sec) Session 2: mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(1,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(2,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(3,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(4,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(5,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(6,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(7,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(8,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(9,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(10,1,1);
Query OK, 1 row affected (0.01 sec) mysql>
mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(11,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(12,1,1);
Query OK, 1 row affected (0.01 sec) 假设一个Index 包含值10,11,13和20,可能的next-key locks 对于这个索引覆盖下面的区间, 一个圆括号表示排除两端,一个方块号报表包含 (negative infinity, 10] 负无穷大
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)正无穷大 测试:
mysql> select * from SmsTest where phoneNo in (10,11,13,20);
+-------+---------+-------------+--------+
| sn | phoneNo | channelType | status |
+-------+---------+-------------+--------+
| 10 | 10 | 2 | 1 |
| 45239 | 10 | 1 | 1 |
| 45252 | 10 | 1 | 1 |
| 11 | 11 | 2 | 1 |
| 45253 | 11 | 1 | 1 |
| 13 | 13 | 2 | 1 |
| 20 | 20 | 2 | 1 |
+-------+---------+-------------+--------+
7 rows in set (0.00 sec) mysql> update SmsTest set phoneNo=999 where phoneNo in (10,11,13,20);
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7 Changed: 7 Warnings: 0 mysql> explain update SmsTest set phoneNo=999 where phoneNo in (10,11,13,20);
+----+-------------+---------+-------+---------------+--------------+---------+-------+------ +------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+--------------+---------+-------+------ +------------------------------+
| 1 | SIMPLE | SmsTest | range | SmsTest_idx1 | SmsTest_idx1 | 4 | const | 7 | Using where; Using temporary |
+----+-------------+---------+-------+---------------+--------------+---------+-------+------ +------------------------------+
1 row in set (0.00 sec) Session 2: mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(1,1,1);
Query OK, 1 row affected (0.01 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(2,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(3,1,1);
Query OK, 1 row affected (0.05 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(4,1,1);
Query OK, 1 row affected (0.01 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(5,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(6,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(7,1,1);
Query OK, 1 row affected (0.01 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(8,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(9,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(10,1,1);--hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(11,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(12,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(13,1,1);--hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(14,1,1);
Query OK, 1 row affected (0.01 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(15,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(16,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(17,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(18,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(19,1,1); mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(20,1,1); --hang mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(21,1,1);
Query OK, 1 row affected (0.01 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(22,1,1);
Query OK, 1 row affected (0.00 sec) mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status) values(23,1,1);
Query1 row affected (0.01 sec) 默认情况下,InnoDB 操作在 REPEATABLE READ transaction isolation level 禁用innodb_locks_unsafe_for_binlog system variable 在这种情况下,使用next-key locks 用于搜索和索引扫描,可以防止幻读

使用next-key locks 用于搜索和索引扫描,可以防止幻读的更多相关文章

  1. Orchard搜索与索引

    Orchard提供了索引与搜索的功能.开启Indexing属性可实现索引功能,伴随着一个特定的索引执行(默认包含基础搜索引擎).除了Indexing和Search提供查询索引的功能外(通过关键字或使用 ...

  2. Key Lookup开销过大导致聚集索引扫描

    以前总结过一篇文章SQL SERVER中什么情况会导致索引查找变成索引扫描 介绍了几种索引查找(Index Seek)变成索引扫描(Index Scan)的情形.昨天写一篇文章的时候,也遇到了一个让人 ...

  3. SQL SERVER中什么情况会导致索引查找变成索引扫描

    SQL Server 中什么情况会导致其执行计划从索引查找(Index Seek)变成索引扫描(Index Scan)呢? 下面从几个方面结合上下文具体场景做了下测试.总结.归纳. 1:隐式转换会导致 ...

  4. mysql使用索引扫描来做排序

    mysql有两种方式可以生成有序的结果,通过排序操作或者按照索引顺序扫描,如果explain的type列的值为index,则说明mysql使用了索引扫描来做排序(不要和extra列的Using ind ...

  5. Oracle 表的访问方式(2)-----索引扫描

    索引扫描(Index scan) 我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值),然后根据rowid直接从表中得到具体的数据,这种查找方式称为索引扫描或索引 ...

  6. MySQL优化GROUP BY-松散索引扫描与紧凑索引扫描

    满足GROUP BY子句的最一般的方法是扫描整个表并创建一个新的临时表,表中每个组的所有行应为连续的,然后使用该临时表来找到组并应用累积函数(如果有).在某些情况中,MySQL能够做得更好,即通过索引 ...

  7. Index Scans 索引扫描

    官方文档链接地址 http://docs.oracle.com/cd/E11882_01/server.112/e40540/indexiot.htm#CNCPT1170 Index Scans 在索 ...

  8. AppBoxFuture: 二级索引及索引扫描查询数据

      数据库索引对于数据查询的重要性不可言喻,因此作者在存储层实现了二级索引,以及利用索引进行扫描的功能.目前仅实现了分区表与非分区表的本地索引(数据与索引共用一个Raft组管理),全局索引及反向索引待 ...

  9. Oracle索引梳理系列(八)- 索引扫描类型及分析(高效索引必备知识)

    版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...

随机推荐

  1. mysqldump备份数据库时出现when using LOCK TABLES

    用mysqldump备份数据库时,如果出现when using LOCK TABLES,解决办法是加上 --skip-lock-tables 例如: 用mysqldump备份数据库时出现 29: Fi ...

  2. [转] git修改author

    Changing author info To change the name and/or email address recorded in existing commits, you must ...

  3. 根据引用jar包路径查找原JAR包

    网站:http://www.findjar.com/. 就是这个网站,经常在网上看到一些好的源码,什么都说了,就是没有说明需要引入那个包,这个包需要从什么地方下载,有些时候在网上搜索还不一定搜索得到, ...

  4. 修改android应用包名 分类: android 学习笔记 2015-07-16 22:48 4人阅读 评论(0) 收藏

    由于项目需要,要修改已经开发好的应用包名,这本身很简单,但是如果你没找到门道,可能会白白浪费许多时间. 修改包名有三个地方要改,这三个地方的修改一定要按顺序来,否则你可能会遇到许多不必要的麻烦. 1. ...

  5. 如何学习一门新技术-iOS开发

    如何快速学习一门新技术 以CoreBluetooth 蓝牙开发为例.我们可以从官方获得的资源有:SampleCode, Documentation,API Reference. 先从Documenta ...

  6. Python开发【第二十篇】:缓存

    Python开发[第二十篇]:缓存redis&Memcache   点击这里 Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy ...

  7. @PostConstruct与@PreDestroy

    从Java EE 5规范开始,Servlet中增加了两个影响Servlet生命周期的注解(Annotion):@PostConstruct和@PreDestroy.这两个注解被用来修饰一个非静态的vo ...

  8. 解决vim不能使用方向键和退格键问题

    1.使用vi命令时,不能正常编辑文件,使用方向键时老是出现很多字母,或者退格键却变成方向键的功能 只要重装一下vi的依赖包即可完美解决vi编辑器方向键变字母的问题.rpm -e vim-enhance ...

  9. java通过移位转16进制

    public class Main { public static void main(String []args) { Main main = new Main(); System.out.prin ...

  10. 英语学习[ZZ]

    本文作者三年间从四级勉强及格到高级口译笔试210,口试232.找工作面试时给其口试的老外考官听了一分钟就说你的英语不用考了.虽不敢说方法一定是最好的,但从现在开始随便谁不要再去找学习资料,每天花两个钟 ...