MySQL的InnoDB的细粒度行锁,是它最吸引人的特性之一。

但是,如《InnoDB,5项最佳实践》所述,如果查询没有命中索引,也将退化为表锁。

InnoDB的细粒度锁,是实现在索引记录上的。

一,InnoDB的索引

InnoDB的索引有两类索引,聚集索引(Clustered Index)与普通索引(Secondary Index)。

InnoDB的每一个表都会有聚集索引:

(1)如果表定义了PK,则PK就是聚集索引;

(2)如果表没有定义PK,则第一个非空unique列是聚集索引;

(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引;

为了方便说明,后文都将以PK说明。

索引的结构是B+树,这里不展开B+树的细节,说几个结论:

(1)在索引结构中,非叶子节点存储key,叶子节点存储value;

(2)聚集索引,叶子节点存储行记录(row);

画外音:所以,InnoDB索引和记录是存储在一起的,而MyISAM的索引和记录是分开存储的。

(3)普通索引,叶子节点存储了PK的值;

画外音:

所以,InnoDB的普通索引,实际上会扫描两遍:

第一遍,由普通索引找到PK;

第二遍,由PK找到行记录;

索引结构,InnoDB/MyISAM的索引结构,如果大家感兴趣,未来撰文详述。

举个例子,假设有InnoDB表:

t(id PK, name KEY, sex, flag);

表中有四条记录:

1, shenjian, www.tianjiuyule178.com m, A

3, zhangsan, www.leyou2.net m, A

5, lisi, m, A

9, wangwu, f, B

以看到:

(1)第一幅图,id PK的聚集索引,叶子存储了所有的行记录;

(2)第二幅图,name上的普通索引,叶子存储了PK的值;

对于:

select * from t where name=’shenjian’;

(1)会先在name普通索引上查询到PK=1;

(2)再在聚集索引衫查询到(1,shenjian, m, A)的行记录;

下文简单介绍InnoDB七种锁中的剩下三种:

  • 记录锁(Record Locks)

  • 间隙锁(Gap Locks)

  • 临键锁(Next-Key Locks)

为了方便讲述,如无特殊说明,后文中,默认的事务隔离级别为可重复读(Repeated Read, RR)。

二、记录锁(Record Locks)

记录锁,它封锁索引记录,例如:

select * from t where id=1www.yongshiyule178.com for update;

它会在id=1的索引记录上加锁,以阻止其他事务插入,更新,删除id=1的这一行。

需要说明的是:

select * from t where id=1;

则是快照读(SnapShot Read),它并不加锁,具体在《InnoDB为什么并发高,读取快?》中做了详细阐述。

三、间隙锁(Gap Locks)

间隙锁,它封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。

依然是上面的例子,InnoDB,RR:

t(id PK, name KEY, sex, flag);

表中有四条记录:

1, shenjian, m, A

3, zhangsan, m, A

5, lisi, m, A

9, wangwu, f, B

这个SQL语句

select * from t

where id between 8 and 15

for update;

会封锁区间,以阻止其他事务id=10的记录插入。

画外音:

为什么要阻止id=10的记录插入?

如果能够插入成功,头一个事务执行相同的SQL语句,会发现结果集多出了一条记录,即幻影数据。

间隙锁的主要目的,就是为了防止其他事务在间隔中插入数据,以导致“不可重复读”。

如果把事务的隔离级别降级为读提交(Read Committed, RC),间隙锁则会自动失效。

四、临键锁(Next-Key Locks)

临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。

更具体的,临键锁会封锁索引记录本身,以及索引记录之前的区间。

如果一个会话占有了索引记录R的共享/排他锁,其他会话不能立刻在R之前的区间插入新的索引记录。

画外音:原文是说

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.

依然是上面的例子,InnoDB,RR:

t(id PK, name KEY, sex, flag);

表中有四条记录:

1, shenjian, m, A

3, zhangsan, m, A

5, lisi, m, A

9, wangwu, f, B

PK上潜在的临键锁为:

(-infinity, 1]

(1, 3]

(3, 5]

(5, 9]

(9, +infinity]

临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。

画外音:关于事务的隔离级别,以及幻读,之前的文章一直没有展开说明,如果大家感兴趣,后文详述。

今天的内容,主要对InnoDB的索引,以及三种锁的概念做了介绍。场景与例子,也都是最简单的场景与最简单的例子。

InnoDB的锁,与索引类型,事务的隔离级别相关,更多更复杂更有趣的案例,后续和大家介绍。

五、总结

(1)InnoDB的索引与行记录存储在一起,这一点和MyISAM不一样;

(2)InnoDB的聚集索引存储行记录,普通索引存储PK,所以普通索引要查询两次;

(3)记录锁锁定索引记录;

(4)间隙锁锁定间隔,防止间隔中被其他事务插入;

(5)临键锁锁定索引记录+间隔,防止幻读;

MySQL的InnoDB的细粒度行锁,是它最吸引人的特性之一。的更多相关文章

  1. [MySQL]InnoDB引擎的行锁和表锁

    1.行锁和表锁 在mysql 的 InnoDB引擎支持行锁,与Oracle不同,mysql的行锁是通过索引加载的,即是行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描, 行锁则 ...

  2. Innodb中的行锁与表锁

    在Innodb引擎中既支持行锁也支持表锁,那么什么时候会锁住整张表,什么时候或只锁住一行呢? InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块 ...

  3. MySQL(27):行锁、表锁、乐观锁、悲观锁

    1. 首先说一下:行锁 和 表锁  主要是针对锁粒度划分的. 一般分为:行锁.表锁.库锁 (1)行锁:访问数据库的时候,锁定整个行数据,防止并发错误. (2)表锁:访问数据库的时候,锁定整个表数据,防 ...

  4. MySQL Internal - InnoDB存储引擎(行结构)

    InnoDB行存储的三个组成部分(说明: F字符表示列的数量) 名称(Name) 大小(Size) Field Start Offsets (F*1) or (F*2) bytes Extra Byt ...

  5. Mysql InnoDB行锁实现方式(转)

    Mysql InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点 ...

  6. Mysql InnoDB行锁实现方式

    Mysql InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点 ...

  7. Mysql研磨之InnoDB行锁模式

    事务并发带来的一些问题 (1)更新丢失(LostUpdate):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题最后的更新覆盖了由其 ...

  8. Mysql InnoDB下的两种行锁

    今天例举2种常见的Mysql InnoDB下的行锁 现有表dr_test(id pk, name) 数据是 1 zhangsan2 lisi3 wangwu 例子1 事务1 update dr_tes ...

  9. mysql:InnoDB行/表级锁实现/事务

    转载:http://book.51cto.com/art/200803/68127.htm 20.3.4 InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL ...

随机推荐

  1. java编程基础——二叉树的镜像

    题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 题目代码 /** * @program: JavaCode * @description: 操作给定的二叉树,将其变换为源二叉树的镜像. * 二 ...

  2. 如何利用WordPress的菜单功能实现友情链接功能?

    导语:对于wordpress网站的友情链接,有很多种方法可以实现,例如我们可以利用WordPress的链接功能,或者利用WordPress的菜单功能.本文章介绍的是如何利用菜单功能来实现友情链接. 前 ...

  3. c++ 程序设计question 001:我们的开发工具是什么?

    我们使用的开发工具是dev cpp (c plus plus),这是一个集成开发环境,我们称之为IDE(integrated development environment)

  4. mysql基础,修改数据表

  5. 【转】html树形菜单控件

    Query plugin: Treeview  这个插件能够把无序列表转换成可展开与收缩的Tree. 主页:http://bassistance.de/jQuery-plugins/jquery-pl ...

  6. DAG上的动态规划——嵌套矩阵问题

    问题描述:有n个矩形,每个矩形可以用两个整数a,b描述,表示它的长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d,或者b<c,a<d(相当于把矩形X旋 ...

  7. 关于IDEA 单元测试时 【empty test suite】异常的分析!!

    IDEA功能很强大,配置很操蛋,自从用了之后掉了很多坑!!! 这几天要用单元测试,方法完好但是就是一直报empty test suite ,WTF,类找不到 在网上反复的找答案都没有合适 静下心想想, ...

  8. time模块和datetime模块详解

    一.time模块 time模块中时间表现的格式主要有三种: a.timestamp时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量 b.struct_time时间元组,共 ...

  9. 2 Model层 -定义模型

    1  ORM简介 MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库 ORM是“对象-关系-映射” ...

  10. Collection record

    复习大集合: 1.函数的参数:位置参数,关键字参数,动态参数 2.命名空间:内置命名空间,全局命名空间,局部命名空间 3.闭包函数:函数引用未定义的函数外非全局的变量叫做闭包,该函数称为闭包函数 4. ...