两万字详解InnoDB的锁( 三 )


比如lock_mode X locks gap before rec表示X型gap锁 。以下就是一个间隙锁的日志:
RECORD LOCKS space id 177 page no 4 n bits 80 index idx_name of table `test2`.`account` trx id 38049 lock_mode X locks gap before recRecord lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 3; hex 576569; asc Wei;; 1: len 4; hex 80000002; asc;;2.5 临键锁(Next-Key Lock)Next-key锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录前面间隙上的锁 。说得更具体一点就是:临键锁会封锁索引记录本身,以及索引记录之前的区间,即它的锁区间是前开后闭,比如(5,10] 。
如果一个会话占有了索引记录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.
2.6 插入意向锁插入意向锁,是插入一行记录操作之前设置的一种间隙锁,这个锁释放了一种插入方式的信号 。它解决的问题:多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此 。
假设有索引值4、7,几个不同的事务准备插入5、6,每个锁都在获得插入行的独占锁之前用插入意向锁各自锁住了4、7之间的间隙,但是不阻塞对方因为插入行不冲突 。以下就是一个插入意向锁的日志:
RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`trx id 8731 lock_mode X locks gap before rec insert intention waitingRecord lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 80000066; ascf;; 1: len 6; hex 000000002215; asc" ;; 2: len 7; hex 9000000172011c; ascr;;...锁模式兼容矩阵(横向是已持有锁,纵向是正在请求的锁):
两万字详解InnoDB的锁

文章插图
 
2.7 自增锁自增锁是一种特殊的表级别锁 。它是专门针对AUTO_INCREMENT类型的列,对于这种列,如果表中新增数据时就会去持有自增锁 。简言之,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值 。
官方文档是这么描述的:
An AUTO-INC lock is a special table-level lock taken by transactions inserting into tables with AUTO_INCREMENT columns. In the simplest case, if one transaction is inserting values into the table, any other transactions must wait to do their own inserts into that table, so that rows inserted by the first transaction receive consecutive primary key values.
假设有表:
mysql> create table t0 (id int NOT NULL AUTO_INCREMENT,name varchar(16),primary key ( id));mysql> show variables like '%innodb_autoinc_lock_mode%';+--------------------------+-------+| Variable_name| Value |+--------------------------+-------+| innodb_autoinc_lock_mode | 1|+--------------------------+-------+1 row in set, 1 warning (0.01 sec)设置事务A和B交替执行流程如下:
两万字详解InnoDB的锁

文章插图
 
通过上图我们可以看到,当我们在事务A中进行自增列的插入操作时,另外会话事务B也进行插入操作,这种情况下会发生2个奇怪的现象:
  • 事务A会话中的自增列好像直接增加了2个值 。(如上图中步骤7、8)
  • 事务B会话中的自增列直接从2开始增加的 。(如上图步骤5、6)
自增锁是一个表级别锁,那为什么会话A事务还没结束,事务B可以执行插入成功呢?不是应该锁表嘛?这是因为在参数innodb_autoinc_lock_mode上,这个参数设置为1的时候,相当于将这种auto_inc lock弱化为了一个更轻量级的互斥自增长机制去实现,官方称之为mutex 。
innodb_autoinc_lock_mode还可以设置为0或者2,
  • 0:表示传统锁模式,使用表级AUTO_INC锁 。一个事务的INSERT-LIKE语句在语句执行结束后释放AUTO_INC表级锁,而不是在事务结束后释放 。
  • 1: 连续锁模式,连续锁模式对于Simple inserts不会使用表级锁,而是使用一个轻量级锁来生成自增值,因为InnoDB可以提前直到插入多少行数据 。自增值生成阶段使用轻量级互斥锁来生成所有的值,而不是一直加锁直到插入完成 。对于bulk inserts类语句使用AUTO_INC表级锁直到语句完成 。
  • ** 2**:交错锁模式,所有的INSERT-LIKE语句都不使用表级锁,而是使用轻量级互斥锁 。
INSERT-LIKE:指所有的插入语句,包括: INSERT、REPLACE、INSERT…SELECT、REPLACE…SELECT,LOAD DATA等 。 Simple inserts:指在插入前就能确定插入行数的语句,包括:INSERT、REPLACE,不包含INSERT…ON DUPLICATE KEY UPDATE这类语句 。 Bulk inserts: 指在插入钱不能确定行数的语句,包括:INSERT … SELECT/REPLACE … SELECT/LOAD DATA 。


推荐阅读