目录
1 共享锁和互斥锁(Shared and Exclusive Locks)
意向互斥锁IX(intention exclusive lock)
一、前言
现代大多数程序都支持多线程并发的访问资源,允许并发访问可以提升CPU利用率 ,但这可能会导致共享资源最终产生与预期不符的结果,对共享资源加锁可以作为这个问题解决方式。
锁是计算机用于协调多线程对共享资源并发访问的一种同步机制,加锁可以保证并发访问共享资源的一致性,所以锁的存在是必要的。MySQL可以用于存储数据,支持多线程处理数据,这可能导致并发问题产生,MySQL实现了许多种锁用于解决并发问题,对这些锁适当的了解可以提升我们对MySQL的使用能力,在产生问题时为我们提供解决思路。
本文主要介绍MySQL的InnoDB存储引擎中各类锁的机制及应用。除特别注明本文之外,其余所有内容都基于MySQL5.7的InnoDB存储引擎。
二、知识点补充
1 事务
InnoDB存储引擎支持事务,默认的隔离级别是可重复读(REPEATABLE READ,以下简称RR),也是使用最多的隔离级别。在RR下,解决了脏读、不可重复读、幻读问题;两个事务同时执行只有写写才会阻塞,在读写、读读、写读情况下都不会相互阻塞。
RR是基于多版本并发控制(Multi-Version Concurrency Control,以下简称MVCC)实现的,InnoDB为数据中的每一行都添加了隐藏列,包括生成当前数据行的事务id(版本号)、指向数据行上一版本记录的回滚指针(数据行每个版本都会通过回滚指针链接上一版本的记录,从而形成版本链)。每开启一个新事务,系统就会为其生成一个事务id(不同事务id,按开启时间顺序递增),基于版本链每次不加锁进行读操作时,会比较行数据的事务id与当前事务id的大小,最终返回查询结果:
- 优先读取数据行事务id等于本事务id的数据(自己修改的);
- 事务A的id小于事务B的id,也就是事务A先于事务B开启,事务B修改了数据,但事务A第一次读取操作在事务B提交之后,事务A可以读取事务B修改的数据行。
- 顺着版本链找到第一个小于当前事务id的版本数据,若改行未被标记被删除,返回此版本。
由上述可知,MVCC可以解决脏读、不可重复读问题,但无法解决幻读问题,InnoDB实现了临键锁用于解决幻读。
2 聚簇索引与非聚簇索引
InnoDB使用B+树作为索引结构,B+树的叶子节点用于存放数据,而它的非叶子节点不存取数据而是存放指向其子节点的指针,且它的叶子结点之间使用指针连接,形成单向链表,适合范围搜索以及顺序读取。
聚簇索引的叶子结点存放了表中完整的数据行,而非聚簇索引的叶子结点存放的是指向的是聚簇索引所在列的索引值。每个表都会有聚簇索引,且只有一个聚簇索引,一般会为主键列创建聚簇索引;如果我们没有显示的为表创建主键,那么会选取第一个创建了唯一索引的列作为聚簇索引;如不存在唯一索引列,InnoDB将会自动生成一个隐藏的主键列,并在此列上创建聚簇索引。
三、InnDB存储引擎之锁分类

注:表中运行的sql都基于此表结构+表数据:
1 共享锁和互斥锁(Shared and Exclusive Locks)
共享锁
共享锁又称为读锁,当前事务获取数据时,发现数据已被加锁,且锁的类型为共享锁时,可为该数据再次添加共享锁,不可添加互斥锁。添加共享锁的数据,可以被并发的读取,但不允许对数据进行修改操作,直到所有的共享锁都被释放。
1)使用:
在RR级别下,使用MVCC不加锁读取数据,这期间允许其他事务修改行数据,就会导致读取的可能不是最新行,当你想读取最新的数据,可以使用 LOCK IN SHARE MODE,显示的为行数据添加共享锁,MySQL会对返回的查询结果中的每行数据都添加共享锁:SELECT * FROM people WHERE id=1 LOCK IN SHARE MODE;
2)例子