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. CGLIB学习笔记

    0 概述 CGLIB基于ASM实现.提供比反射更为强大的动态特性.使用CGLIB可以非常方便的实现的动态代理. 0.1 CGLIB包结构 net.sf.cglib.core    底层字节码处理类. ...

  2. 9.28noip模拟试题

    1.栅栏迷宫 田野上搭建了一个黄金大神专用的栅栏围成的迷宫.幸运的是,在迷宫的边界上留出了两段栅栏作为迷宫的出口.更幸运的是,所建造的迷宫是一个“完美的”迷宫:即你能从迷宫中的任意一点找到一条走出迷宫 ...

  3. ASP.NET MVC 第四回 向View传值

    一.ViewData与TempData属性来向View页传递对象 上文中已经提到,使用ViewData可以将数据由Controller传递到View 在前文中我们建立了EiceController类  ...

  4. MVC4将Controller与views分开

    最近自己在要着手从头做一个项目,自己想把mvc里的view和controller文件分别写在不同的项目里,刚开始在网上找了下,可是不尽理想,最后翻了一下自己以前参加的项目找到了这个做法. 这个需要在G ...

  5. postgresql jsonb类型查询

    select * from (select * from ud_order where user_id=10 and status=2unionselect * from ud_order where ...

  6. 使用EMMET中的小坑

    使用EMMET写HTML的时候,是一个非常爽的事情.但是今天我使用时,发现一个小坑.以前倒也没有注意,不过需要非常的小心. form[action="/process" metho ...

  7. 查询Sqlserver数据库死锁的一个存储过程(转)

        使用sqlserver作为数据库的应用系统,都避免不了有时候会产生死锁, 死锁出现以后,维护人员或者开发人员大多只会通过sp_who来查找死锁的进程,然后用sp_kill杀掉.利用sp_who ...

  8. 使用OC开发phonegp 组件

    使用OC开发phonegp 组件 1. 使用oc 对phonegp中的组件近些开发,首先具体的pgonegp跟nativecode之间的一些优劣就不说了,开发phonegp 对应的组件主要就是使用na ...

  9. JavaScript Window - 浏览器对象模型

    浏览器对象模型 (BOM) 使 JavaScript 有能力与浏览器"对话". 浏览器对象模型 (BOM) 浏览器对象模型(Browser Object Model (BOM))尚 ...

  10. windowsphone 中CollectionViewSource和ObservableCollection的使用

    功能描述:一级菜单省份  联动显示省份下的城市 直接上代码 public class City { public string Num { get; set; } public string Name ...