InnoDB 锁
参看文章:
- innodb的意向锁有什么作用?
2.《MySQL技术内幕:InnoDB存储引擎》
InnoDB存储引擎中的锁
InnoDB中的锁介绍
InnoDB存储引擎既支持行级锁,也支持表级锁,默认情况下采用行级锁。
InnoDB的锁类型有:共享锁(S Lock)、排他锁(X Lock)、意向共享锁(IS Lock)、意向排他锁(IX Lock)。
共享锁和排他锁非常简单,下面我们主要讲一下意向锁:
百度百科的解释:意向锁的含义是如果对一个节点加意向锁,则说明该节点的下层节点正在被加锁;对任意一节点加锁时,必须先对它的上层节点加意向锁。
在InnoDB中,为了既支持表级锁也支持行级锁,甚至支持行级锁和表级锁同时存在。所以在加行级锁的同时,会对整个表加上意向锁;如果同时有请求对表加表锁时:
- 如果没有意向锁的话,则需要遍历整个表判断是否有行锁的存在,以免发生冲突。
- 如果有了意向锁,只需要判断该意向锁与即将添加的表锁是否兼容即可。因为意向锁的存在代表了有行级锁的存在或者即将有行级锁的存在。
简而言之,意向锁就是为了让表锁快速感知到是否有行锁存在,以防表锁干扰到行锁的执行。
意向锁是一种表级锁,锁的粒度是整张表,主要分为意向共享锁(IS Lock)和意向排他锁(IX Lock)。意向锁是不会阻塞除全表扫描之外的任何请求。
两个意向排他锁或者意向排他锁之间都是相互兼容的,除非它们都需要对相同行加真实的排他锁。
IS and IX locks allow access by multiple clients. They won't necessarily conflict until they try to get real locks on the same rows。But a table lock (ALTER TABLE, DROP TABLE, LOCK TABLES) blocks both IS and IX, and vice-versa.
若将上锁的对象看成一棵树,那么对最下层的对象上锁,也就是对最细粒度的对象进行上锁,那么首先需要对粗粒度的对象上锁。如下图,当我们要对记录加上排他锁时,那么我们先要对数据库A、表、页都加上意向排他锁,最后再对记录加上排他锁,若其中任何一部分导致等待,那么该操作需要等待粗粒度锁的完成。
InnoDB中锁的实现算法
InnoDB存储引擎有3种行锁的算法设计,分别是:
- Record Lock:单个行记录上的锁。
- Gap Lock:间隙锁,锁定一个范围,但不包括记录本身。GAP锁的目的,是为了幻读的问题。
- Next-Key Lock:Gap Lock + Record Lock。锁定一个范围,并且锁定记录本身。
Record Lock总是会去锁住索引记录。如果InnoDB存储引擎表建立的时候没有设置任何一个索引,这时InnoDB存储引擎会使用隐式的主键来进行锁定。
InnoDB中对于行的查询都是采用Next-Key Lock锁定算法。对于不同SQL查询语句,可能设置共享的(Share) Next-Key Lock和排他的(exlusive) Next-Key Lock,其主要目的也是为了解决幻行问题。但当查询的索引含有全部唯一属性(主键或唯一索引)时InnoDB存储引擎会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围,从而提高应用的并发性。也就是说InnoDB存储引擎会自己选一个最小的算法模型。
但是如果查询的条件中包含的是辅助索引,则情况会完全不同,会产生如下锁情况:
- 首先会对辅助索引对应的主键索引加上Record Lock。
- 对辅助索引加上Next-Key Lock,锁定辅助索引的前一个区间。
- 对辅助索引的下一个区间加上gap Lock。
下面是一个示例:
我们知道InnoDB默认的事务隔离级别为REPEATABLE READ模式,而REPEATABLE READ模式下,Next-Key Lock算法又是默认的行记录锁定算法,所以就可以避免幻读的现象。