MySQL的InnoDB的细粒度行锁是它最吸引人的特性之一。但是,《InnoDB,5项***实践》所提到的,如果查询没有活动索引,也会退化为表锁。InnoDB的细粒度锁是在索引记录上实现的。1.InnoDB索引InnoDB索引中有两种索引,聚集索引(ClusteredIndex)和普通索引(SecondaryIndex)。InnoDB中的每张表都会有一个聚簇索引:如果表定义了PK,那么PK就是聚簇索引;如果表没有定义主键,第一个非空唯一列是聚簇索引;否则,InnoDB将创建一个隐藏的行-id用作聚簇索引;为了描述方便,下面以PK来描述。索引的结构是B+树。B+树的细节这里就不展开了,只做几点总结:(1)在索引结构中,非叶子节点存放键,叶子节点存放值;(2)聚簇索引,叶子节点存放行记录(row);画外音:因此,InnoDB的索引和记录是放在一起的,而MyISAM的索引和记录是分开存放的。(3)普通索引,叶子节点存放PK的值;画外音:因此,InnoDB的普通索引实际上会扫描两次:第一次,PK被普通索引找到;第二次,通过PK找到行记录;Index结构,InnoDB/MyISAM的索引结构,有兴趣的我以后会写一篇文章详细介绍。例如,假设有一张InnoDB表:t(idPK,nameKEY,sex,flag)表中有4条记录:1,shenjian,m,A3,zhangsan,m,A5,lisi,m,A9,wangwu,f,B可以看到:第一张图,idPK的聚簇索引,叶子存储所有的行记录;第二张图,name上的commonindex,叶子里存放的是PK的值;for:select*fromtwherename='shenjian会先在name普通索引上查询PK=1;然后在聚簇索引中查询(1,shenjian,m,A)的行记录;下面简单介绍一下InnoDB七种锁中剩下的三种:RecordLocksGapLocksNext-KeyLocks为方便描述,如无特殊说明,下文中默认的事务隔离级别为RepeatedRead(RR)。2.记录锁(RecordLocks)记录锁,阻塞索引记录,例如:select*fromtwhereid=1forupdate会锁住id=1的索引记录,防止其他事务插入、更新、删除id的索引记录=1一行。需要说明的是:select*fromtwhereid=1是快照读取(SnapShotRead),不加锁,在《InnoDB为什么并发高,读取快?》中有详细说明。3.GapLocks间隙锁,阻塞索引记录中的区间,或者第一条索引记录之前的范围,或者最后一条索引记录之后的范围。还是上面的例子,InnoDB,RR:t(idPK,nameKEY,sex,flag)表中有4条记录:1、shenjian、m、A3、zhangsan、m、A5、lisi、m、A9、wangwu,f,BSQL语句select*fromtwhereidbetween8and15forupdate会阻塞区间,防止插入其他事务id=10的记录。画外音:为什么要阻止插入id=10的记录?如果插入成功,第一个事务执行相同的SQL语句,你会发现结果集中多了一条记录,也就是幻像数据。间隙锁的主要目的是防止其他事务在间隙中插入数据,造成“不可重复读”。如果事务的隔离级别降为ReadCommitted(RC),间隙锁会自动失效。4.Next-KeyLocksNext-KeyLocks是记录锁和间隙锁的组合。它的阻塞范围包括索引记录和索引区间。更具体地说,临时键锁会阻塞索引记录本身,以及索引记录之前的间隔。如果一个session对索引记录R持有共享锁/排他锁,其他session不能立即在R之前的区间插入新的索引记录。画外音:原文说如果一个session对某个索引中的记录R持有共享锁或排它锁,另一个会话不能在索引顺序中R之前的间隙中插入新的索引记录。还是上面的例子,InnoDB,RR:t(idPK,nameKEY,sex,flag)表中有4条记录:1、shenjian、m、A3、zhangsan、m、A5、lisi、m、A9、wangwu,f,potentialkeylockonBPKFor:(-infinity,1](1,3](3,5](5,9](9,+infinity]keylock的主要目的也是为了避免幻读(幻读)如果事务的隔离级别降为RC,key锁也会失效画外音:关于事务的隔离级别和幻读,之前的文章没有说明,有兴趣的可以,后面会详细介绍,今天的内容主要是关于InnoDB的索引,介绍三种锁的概念,场景和例子也是最简单的场景和最简单的例子,InnoDB的锁跟索引类型和索引的隔离级别有关transaction.更多、更复杂、更有趣的案例,后面会介绍给大家。五、总结InnoDB的索引和行记录是存储在一起的,这一点与MyISAM不同;InnoDB的聚集索引存储行记录,普通索引存储PK,所以普通索引需要查询两次;记录锁锁索引记录;gaplockslockInterval,防止区间被其他事务插入;Prokeylock锁定索引记录+区间,防止幻读;【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此查看更多作者好文
