一、意向锁简介
InnoDB 存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
InnoDB行锁是通过给索引上的索引项加锁来实现的,InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁。
行级锁的缺点是:由于针对的是单行记录(实际是对索引项加锁),如果表内的数据量特别大,在一些情况下需要请求大量的锁资源,所以速度慢,内存消耗大。以及某些情况下需要对全表扫描是哪些行加了锁。
为了支持在不同粒度上进行加锁操作(允许行锁和表锁共存,实现多粒度锁机制),InnoDB 还有两种存储引擎内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。
首先,在介绍意向锁之前,回顾一下共享锁和排他锁:
共享锁(S-shared):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。排他锁(X-exclusive):只允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
意向共享锁和意向排他锁:
意向共享锁(IS- intent share lock):如果某个事务想要获得(意向)一张表中某几行的共享锁,那么这个事务在给数据行加共享锁前必须先取得该表的 IS 锁。意向排他锁(IX -intent exclusive lock):如果某个事务想要获得(意向)一张表中某几行的排他锁,那么这个事务在给数据行加排他锁前必须先取得该表的 IX 锁。
由于InnoDB存储引擎支持的是行级别的锁,因此除了全表扫描之外,意向锁其实不会阻塞任何请求。故表级意向锁与行级锁的兼容性如下所示:
可以看到当前锁不管是IS还是IX,请求锁如果是IS或者IX都不阻塞。
二、意向锁的作用
假设事务B要在一个表上加S锁,如果表中的某一行已被事务A加了X锁,那么该锁的申请也应被阻塞。如果表中的数据很多,逐行检查锁标志的开销将很大,系统的性能将会受到影响。为了解决这个问题,可以在表级上引入新的锁类型来表示其所属行的加锁情况,这就引出了“意向锁”的概念。
举个例子:
假设不存在意向锁,如果表中记录1亿,事务A已经把其中有几条记录上了行锁了,这时事务B需要给这个表加表级锁,那就要去表中查找这一亿条记录哪些记录上了行锁了,效率不高。
假设存在意向锁,如果表中记录1亿,事务A在更新一条记录时,对表加上IX锁,然后对这条记录加了X锁,。假设此时事务B需要加锁了:
加行级或表级X锁:同时也会先对表加IX锁,由于当前表之前被事务A加了IX锁。IX和IX不冲突,所以事务B可以继续获取锁。加行级或表级S锁:同时也会先对表加IS锁,由于当前表之前被事务A加了IX锁。IX和IS不冲突,所以事务B可以继续获取锁。
后面的事务B需要给这个表加锁时,那么会先判断表存在的意向锁是否与自己准备加的锁冲突,如果有冲突,则等待直到事务A释放,而无须逐条记录去检测。事务B更新表时,其实无须知道到底哪一行被锁了,它只要知道反正有一行被锁了就行了。这样相比较不存在意向锁的情况,大大减少了查找行锁的时间。
所以意向锁的主要作用其实就是处理行锁和表锁之间的矛盾,能够显示“某个事务正在某一行上持有了锁,或者准备去持有锁”,而不需要具体查找是哪一行加了锁,从而提高了性能。
THE END.