參考http://blog.csdn.net/zbszhangbosen/article/details/7434637#reply

这里补充一些:

(1)InnoDB默认加锁方式是next-key locking

(2)在聚集索引中,假设主键有唯一性约束(unique,auto increment),next-key locking 会自己主动降级为record locking。

(3)因为事务的隔离性和一致性要求,会对全部扫描到的record加锁。

比方:update ... where/delete .. where/select ...from...lock in share mode/ select .. from .. for update这都是next-key lock。

(4)注意优化器的选择。

包含聚集索引和辅助索引。有时会用全表扫描替代索引扫描。这时整张表(聚集索引表)都会被加锁。

record lock:记录锁,也就是只锁着单独的一行

gap lock:区间锁。只锁住一个区间(注意这里的区间都是开区间。也就是不包含边界值,至于为什么这么定义?innodb官方定义的)

next-key lock:record lock+gap lock,所以next-key lock也就半开半闭区间,且是下界开,上界闭。(为什么这么定义?innodb官方定义的)

以下来举个手冊上的样例看什么是next-key lock。

假如一个索引的行有10,11,13,20

那么可能的next-key lock的包含:

(无穷小, 10]

(10,11]

(11,13]

(13,20]

(20, 无穷大) (这里无穷大为什么不是闭合?你数学不到家~~)

好了如今通过举样例说明:





表test

mysql> show create table test;

+-------+--------------------------------------------------------------------------------------------------------+

| Table | Create Table                                                                                           |

+-------+--------------------------------------------------------------------------------------------------------+

| test  | CREATE TABLE `test` (

  `a` int(11) NOT NULL,

  PRIMARY KEY (`a`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

+-------+--------------------------------------------------------------------------------------------------------+

1 row in set (0.00 sec)

mysql> select * from test;

+----+

| a  |

+----+

| 11 |

| 12 |

| 13 |

| 14 |

+----+

4 rows in set (0.00 sec)

開始实验:

(一)

session 1:

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)





mysql> delete from test where a=11;

Query OK, 1 row affected (0.00 sec)





session 2:

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)





mysql> insert into test values(10);

Query OK, 1 row affected (0.00 sec)





mysql> insert into test values(15);

Query OK, 1 row affected (0.00 sec)





mysql> insert into test values(9);

Query OK, 1 row affected (0.00 sec)





mysql> insert into test values(16);

Query OK, 1 row affected (0.01 sec)





mysql> rollback;

Query OK, 0 rows affected (0.00 sec)





ok,上面的情况是预期的。由于a上有索引。那么当然就仅仅要锁定一行,所以其它行的插入不会被堵塞。

那么接下来的情况就有意思了

(二)

session 1(跟上一个session 1同样):

delete from test where a=22;

Query OK, 0 rows affected (0.01 sec)





session 2:

mysql> insert into test values (201);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test values (20);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test values (19);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test values (18);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test values (16);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test values (9);

Query OK, 1 row affected (0.00 sec)





从上面的结果来看,在a=11后面全部的行,也就是区间(11,无穷大)都被锁定了。先不解释原因,再来看一种情况:

(三)

session 1:

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)





mysql> select * from test;

+----+

| a  |

+----+

|  7 |

|  9 |

| 10 |

| 12 |

| 13 |

| 14 |

| 15 |

| 22 |

| 23 |

| 24 |

| 25 |

+----+

11 rows in set (0.00 sec)





mysql> delete from test where a=21;

Query OK, 0 rows affected (0.00 sec)





session 2:

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)





mysql> insert into test values (20);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test values (26);

Query OK, 1 row affected (0.00 sec)





mysql> insert into test values (21);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test values (16);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test values (6);

Query OK, 1 row affected (0.01 sec)





从这里能够看出。如今被锁住的区间就仅仅有[16,21)了。

有了前面对三种类型的加锁解释,如今能够来解释为什么会这样了,在innodb表中 delete from where ..针对扫描到的索引记录加next-key锁(详细的什么语句加什么锁能够查看手冊,另外须要说明一下。行锁加锁对象永远是索引记录,由于innodb中表即索引) 。

在(一)中。实际上加的next-key lock就是(11,11] 因此也仅仅有a=11这一条记录被锁住。其它全部插入都没有关系。

在(二)中,由于a=22这条记录不存在,并且22比表里全部的记录值都大,所以在innodb看来锁住的区间就是(14, 无穷大)。

所以在插入14以后的值都提示被锁住,而14之前的则能够。

在(三)种。a=21也是不存在,可是在表里面21前后都有记录。因此这里next-key lock的区间也就是(15,21],因此不在这个区间内的都能够插入。

那么为什么next-key lock都是下界开区间。上界闭区间呢?这个倒不重要,管它呢,可是有一点我个人却认为比較怪,比方说

delete test where a > 11           #------- 1

它的next-key lock是(11, 无穷大) 

delete test where a < 11           #------- 2

它的next-key lock是(无穷小, 10]

这样给人的感觉就非常怪。由于在手冊上对next-key lock的定义:

Next-key lock: This is a combination of a record lock on the index record and a gap lock on the gapbefore the index record.

而在1那种情况下,如果依照手冊上的解释,记录锁和它之前的gap那么就会有些牵强。

[今天再次看了一遍官方手冊,是之前自己的理解不到位,这个before是对的,由于innodb在加锁时是全部扫描过程中遇到的记录都会被加锁,那么对于1那种情况,实际上是从12開始扫描,可是由于要保证a>11的都被delete掉。因此得一直扫描下去那自然最大值就是无穷大,由于这个next-key lock就是无穷大这条记录(这是如果的一条记录,表示一个边界)加上它之前的gap lock (11, 无穷大),所以在不论什么时候next-lock都是record
lock加上这个record之前的一个gap lock]

可是仅仅要我们自己能理解即可了:记录锁---锁单条记录。区间锁---锁一个开区间。next-key 锁---前面两者的结合,而不要管什么before。

另外next-key lock尽管在非常多时候是锁一个区间,但要明确一个区间也可能仅仅有一个元素。因此在称delete from tb where key=x 这样的情况下加next-key锁也是全然正确的。

另外还提两点:

1.假设我们的SQL语句里面没有利用到索引。那么加锁对象将是全部行(但不是加表锁)。所以建索引是非常重要的

2.next-key lock是为防止幻读的发生,而仅仅有repeatable-read以及以上隔离级别才干防止幻读。所以在read-committed隔离级别以下没有next-key lock这一说法。

innodb next-key lock解析的更多相关文章

  1. InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析

    InnoDB锁机制之Gap Lock.Next-Key Lock.Record Lock解析 有意思,解释的很好

  2. 关于InnoDB的Next-Key lock

    最近一段时间在准备新员工培训的材料,本来打算介绍介绍概念就OK的,但是既然写了事务的章节,就特别想介绍一下锁,介绍了锁,就忍不住想介绍一下Next-Key Lock. 大家知道,标准的事务隔离级别有R ...

  3. Key lock 的秘密

    研究死锁,或者观察sp_lock,有时候最恼人的莫过于你看到下面研究成果的key lock,但是却不知道究竟是哪个page 哪个row被lock住了: Exec sp_lock:   就说上面的key ...

  4. mysql之 [ERROR] InnoDB: Unable to lock ./ibdata1, error: 11

    问题描述:启动MySQL后,出现连接不上,报 [ERROR] InnoDB: Unable to lock ./ibdata1, error: 11[root@mysql01 ~]# service ...

  5. MySQL InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析

    MySQL InnoDB支持三种行锁定方式: l   行锁(Record Lock):锁直接加在索引记录上面,锁住的是key. l   间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙 ...

  6. my39_InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析

    MySQL InnoDB支持三种行锁定方式: 行锁(Record Lock):锁直接加在索引记录上面,锁住的是key. 间隙锁(Gap Lock): 锁定索引记录间隙,确保索引记录的间隙不变.间隙锁是 ...

  7. 从ext4将mysql数据目录移动至lustre出现(InnoDB: Unable to lock ./ibdata1, error: 38.)

    因为数据目录过大,因此我把目录从本地移到了共享存储中.在修改了/etc/my.cnf和/etc/init.d/mysqld之后发现数据库可以运行,但启动速度很慢 原因是原文件系统是ext4,而目标文件 ...

  8. MySQL InnoDB primary key根节点常驻内存

    mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作.

  9. MySQL · 引擎特性 · InnoDB index lock前世今生

    http://mysql.taobao.org/monthly/2015/07/05/ MySQL · 引擎特性 · InnoDB index lock前世今生 前言 InnoDB并发过程中使用两类锁 ...

随机推荐

  1. 关于APP上架制作二维码相关

    1.安卓版本APP上架并生成二维码问题:安卓版本上架国内市场,这个情况比较复杂一些,比如百度,网址是以上传APP生成的一个编号来进行的,每次升级更新后都发生了变化,也就相当于每次升级后网址发生改变(比 ...

  2. mysql python中的pymysql模块使用

    import pymysql # 在这之前需要给mysql授登录权限 grant all on "; 否则会导致连接时出错 # flush privileges; #创建连接 conn = ...

  3. Android 使用TabLayout、ViewPager和Fragment实现顶部菜单可滑动切换

    效果图如下 首先,要使用控件需要添加design library,在Android Studio中添加 compile 'com.android.support:design:23.4.0' 然后是布 ...

  4. Vue中对data的操作

    1. {{a}} var vm = new Vue({ el: '#app', data: { a: { a: 1, b: 2 } } })   vm.a.c = 'sadoisad' // 按理说是 ...

  5. Swift学习笔记(7)--控制流

    1.For循环 //1.条件递增 for var index = 0; index < 3; ++index { println("index is \(index)") } ...

  6. LintCode-最大子数组差

    给定一个整数数组,找出两个不重叠的子数组A和B,使两个子数组和的差的绝对值|SUM(A) - SUM(B)|最大. 返回这个最大的差值. 您在真实的面试中是否遇到过这个题? Yes 例子 给出数组[1 ...

  7. Onvif开发之服务端发现篇

    服务端的开发相对来说比客户端稍微难一点,也就是给填充相关结构体的时候,需要一点一点的去查阅,验证各个结构中各个成员各自代表什么意思,以及对应的功能需要是那个接口实现,这是开发服务端最头疼的事情.(在开 ...

  8. es6 -- Iterator 和 for...of 循环

    1:Iterator(遍历器)的概念 JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set.这样就有了四种数据集合,用户还 ...

  9. Zabbix自动发现与自动注册.

    一, 自动发现与自动注册 自动发现? 当场景中出现要添加很多台主机的时候,一台台添加难免太过于繁琐,zabbix提供自动注册,自动发现,可以实现主机的批量添加, zabbix的发现包括三种类型: # ...

  10. words2

    餐具:coffee pot 咖啡壶coffee cup 咖啡杯paper towel 纸巾napkin 餐巾table cloth 桌布tea -pot 茶壶tea set 茶具tea tray 茶盘 ...