InnoDB Record, Gap, and Next-Key Locks
InnoDB
has several types of record-level locks including record locks, gap locks, and next-key locks. For information about shared locks, exclusive locks, and intention locks, see Section 14.3.5.3, “InnoDB
Lock Modes”.InnoDB有几种行级锁类型, 包括 record 锁, gap 锁, next-key锁.
-
Record lock: This is a lock on an index record.
- Record lock: 这是一个索引上的锁
-
Gap lock: This is a lock on a gap between index records, or a lock on the gap before the first or after the last index record.
- Gap lock: 这是一个索引记录区间上的锁, 或者一个在第一条索引记录之前或最后一条索引记录之后的间隙上的锁
-
Next-key lock: This is a combination of a record lock on the index record and a gap lock on the gap before the index record.
- Next-key lock: 这是一个index的record lock和在这个index之前的间隙的gap lock的组合
Record Locks
Record locks always lock index records, even if a table is defined with no indexes. For such cases, InnoDB
creates a hidden clustered index and uses this index for record locking. See Section 14.3.5.13.2, “Clustered and Secondary Indexes”.
record locks 总是锁定索引记录, 即使一个表并没有定义索引.这种情况下, InnoDB创建了一个隐藏的clustered索引, 并用这个索引来进行record locking.
Next-key Locks
By default, InnoDB
operates in REPEATABLE READ
transaction isolation level and with theinnodb_locks_unsafe_for_binlog
system variable disabled. In this case, InnoDB
uses next-key locks for searches and index scans, which prevents phantom rows (see Section 14.3.5.7, “Avoiding the Phantom Problem Using Next-Key Locking”).
默认的, InnoDB工作于REPEATABLE READ事务隔离级别并且innodb_locks_unsafe_for_binlog系统变量是disabled的.在这种情况下, InnoDB使用next-key locks来查找和索引扫描, 这阻止了幻读的产生.
Next-key locking combines index-row locking with gap locking. InnoDB
performs row-level locking in such a way that when it searches or scans a table index, it sets shared or exclusive locks on the index records it encounters. Thus, the row-level locks are actually index-record locks. In addition, a next-key lock on an index record also affects the “gap” before that index record. That is, a next-key lock is an index-record lock plus a gap lock on the gap preceding the index record. 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.
Next-key locking 组合了 index-row locking 和 gap locking. InnoDB在搜索或者扫描表索引时使用了行级锁定, 他在遇到的索引记录上设置共享或排他锁. 因此, 行级锁实际上是索引记录锁.另外, 一个索引上的next-key锁也会影响index记录之前的"gap", 那就是, 一个 next-key锁是一个index-record lock 加上一个 gap lock, 它位于指定索引及索引之前的间隙, 形如 (a, b]. 如果一次护花拥有一个记录行R的索引的共享或排他锁, 另外一个会话将不能插入新索引行到间隙之间.
Suppose that an index contains the values 10, 11, 13, and 20. The possible next-key locks for this index cover the following intervals, where (
or )
denote exclusion of the interval endpoint and [
or ]
denote inclusion of the endpoint:
假设索引包含10,11,13,20. 可能的next-key locks覆盖如下间隔, ()表示排除, []表示包含
(negative infinity, 10] (10, 11] (11, 13] (13, 20] (20, positive infinity)
For the last interval, the next-key lock locks the gap above the largest value in the index and the “supremum”pseudo-record having a value higher than any value actually in the index. The supremum is not a real index record, so, in effect, this next-key lock locks only the gap following the largest index value.
对于最后一个间隔, next-key lock 锁定了大于最大值的所有间隙, 并且上界是一个假的大于任何已有值的值. 上界并不是一个真的索引记录, 所以, next-key lock只锁定了最大值以上的值.
Gap Locks
The next-key locking example in the previous section shows that a gap might span a single index value, multiple index values, or even be empty.
上面的next-key locking 例子展示了一个gap可能会跨越单个索引值, 多个索引值, 或者是空
Gap locking is not needed for statements that lock rows using a unique index to search for a unique row. (This does not include the case that the search condition includes only some columns of a multiple-column unique index; in that case, gap locking does occur.) For example, if the id
column has a unique index, the following statement uses only an index-record lock for the row having id
value 100 and it does not matter whether other sessions insert rows in the preceding gap:
Gap locking在使用唯一索引来查找一个唯一行是不需要的.(这不包括查找中仅仅包含一些多列唯一索引的列的情况, 这种情况下, 间隙锁会发挥作用.) 例如, 如果id列有一个唯一索引, 下面的语句仅仅会使用index-record lock, 使用的范围是id值100, 并不会阻止其他会话在100之前插入记录
SELECT * FROM child WHERE id = 100;
If id
is not indexed or has a nonunique index, the statement does lock the preceding gap.
如果id不是索引, 或者只有一个非唯一索引, 那么语句就会使用间隙锁.
A type of gap lock called an insertion intention gap lock is set by INSERT
operations prior to row insertion. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap. Suppose that there are index records with values of 4 and 7. Separate transactions that attempt to insert values of 5 and 6 each lock the gap between 4 and 7 with insert intention locks prior to obtaining the exclusive lock on the inserted row, but do not block each other because the rows are nonconflicting. For more information about intention locks, seeSection 14.3.5.3, “InnoDB
Lock Modes”.
有一种间隙锁叫插入意向间隙锁, 他是由INSERT语句对行的插入产生的. 这个锁表示了如果有多个事务打算插入记录到同一个索引间隙, 他们不需要彼此等待, 只要他们插入的位置不是同一个位置. 想象有索引记录4,7.有两个事务试图插入5,6, 他们都使用插入意向锁锁住了4,7之间的间隙来获取插入行的排他锁,但是他们并不会相互阻塞, 因为行之间并不会冲突.
It is also worth noting here that conflicting locks can be held on a gap by different transactions. For example, transaction A can hold a shared gap lock (gap S-lock) on a gap while transaction B holds an exclusive gap lock (gap X-lock) on the same gap. The reason conflicting gap locks are allowed is that if a record is purged from an index, the gap locks held on the record by different transactions must be merged.
值得一提的是冲突的锁可以被不同的事务在同一个间隙中持有. 例如, 事务A可以在一个间隙上持有一个共享间隙锁, 同时事务B可以也可以在该间隙上持有一个排他间隙锁. 这种情形被允许的原因是如果一条记录从索引中清除了, 不同事务持有的这条记录上的gap锁必须被合并
Gap locks in InnoDB
are “purely inhibitive”, which means they only stop other transactions from inserting to the gap. Thus, a gap X-lock has the same effect as a gap S-lock.
gap locks 在innodb中是"完全被抑制的", 这意味着他们仅仅阻止其他事务在间隙中执行插入操作.因此, 一个gap X-lock的效果和一个gap S-lock是一样的.
Disabling Gap Locking
Gap locking can be disabled explicitly. This occurs if you change the transaction isolation level to READ COMMITTED
or enable the innodb_locks_unsafe_for_binlog
system variable. Under these circumstances, gap locking is disabled for searches and index scans and is used only for foreign-key constraint checking and duplicate-key checking.
Gap locking是可以被显式禁用的. 你讲事务隔离级别设置为READ_COMMITTED或者启用innodb_locks_unsafe_for_binlog系统变量时就可以禁用它.在这种情况下, gap locking在查找和索引扫描的时候会被禁用, 仅仅在外键约束检查和重复键检查时被使用.
There are also other effects of using the READ COMMITTED
isolation level or enablinginnodb_locks_unsafe_for_binlog
: Record locks for nonmatching rows are released after MySQL has evaluated the WHERE
condition. For UPDATE
statements, InnoDB
does a “semi-consistent” read, such that it returns the latest committed version to MySQL so that MySQL can determine whether the row matches the WHERE
condition of the UPDATE
.
还有些别的副作用: 没有匹配行的Record locks在MYSQL评估完WHERE语句后会被释放.对于UPDATE, innodb做了一次"半一致"读, 它返回最后提交的版本给MYSQL, 这样MSYQL可以判断这一行是否匹配UPDATE的WHERE条件.