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.6.1, “InnoDB Lock Modes”.
Record lock: This is a lock on an index record.
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.
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.
Record locks always lock index records, even if a table is defined
with no indexes. For such cases,
a hidden clustered index and uses this index for record locking.
See Section 22.214.171.124, “Clustered and Secondary Indexes”.
InnoDB operates in
REPEATABLE READ transaction
isolation level and with the
system variable disabled. In this case,
uses next-key locks for searches and index scans, which prevents
phantom rows (see Section 14.6.3, “Avoiding the Phantom Problem Using Next-Key Locking”).
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
R in an index, another session cannot
insert a new index record in the gap immediately before
R in the index order.
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 a round bracket denotes exclusion of the interval endpoint and a square bracket denotes inclusion of the endpoint:
(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.
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.
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
SELECT * FROM child WHERE id = 100;
id is not indexed or has a nonunique index,
the statement does lock the preceding gap.
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.
Gap locks in
InnoDB are “purely
inhibitive”, which means they only stop other transactions
from inserting to the gap. They do not prevent different
transactions from taking gap locks on the same gap. Thus, a gap
X-lock has the same effect as a gap S-lock.
A type of gap lock called an insert
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, respectively, 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
The following example demonstrates a transaction taking an insert intention lock prior to obtaining an exclusive lock on the inserted record. The example involves two clients, A and B.
Client A creates a table containing two index records (90 and 102) and then starts a transaction that places an exclusive lock on index records with an ID greater than 100. The exclusive lock includes a gap lock before record 102:
CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;mysql>
INSERT INTO child (id) values (90),(102);mysql>
SELECT * FROM child WHERE id > 100 FOR UPDATE;+-----+ | id | +-----+ | 102 | +-----+
Client B begins a transaction to insert a record into the gap. The transaction takes an insert intention lock while it waits to obtain an exclusive lock.
INSERT INTO child (id) VALUES (101);
To view data about the insert intention lock, run
SHOW ENGINE INNODB
STATUS. Data similar to the following appears under the
SHOW ENGINE INNODB STATUS\G... SHOW ENGINE INNODB STATUS ---TRANSACTION 8731, ACTIVE 7 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s) MySQL thread id 3, OS thread handle 0x7f996beac700, query id 30 localhost root update INSERT INTO child (id) VALUES (101) ------- TRX HAS BEEN WAITING 7 SEC FOR THIS LOCK TO BE GRANTED: 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 waiting Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 80000066; asc f;; 1: len 6; hex 000000002215; asc " ;; 2: len 7; hex 9000000172011c; asc r ;;...
Gap locking can be disabled explicitly. This occurs if you change
the transaction isolation level to
COMMITTED or enable the
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.
There are also other effects of using the
READ COMMITTED isolation level
Record locks for nonmatching rows are released after MySQL has
WHERE condition. For
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