This section describes lock types used by
T1 holds a shared
S) lock on row
then requests from some distinct transaction
T2 for a lock on row
handled as follows:
A request by
Slock can be granted immediately. As a result, both
A request by
Xlock cannot be granted immediately.
If a transaction
T1 holds an exclusive
X) lock on row
a request from some distinct transaction
for a lock of either type on
r cannot be
granted immediately. Instead, transaction
has to wait for transaction
T1 to release its
lock on row
InnoDB supports multiple
granularity locking which permits coexistence of
row-level locks and locks on entire tables. To make locking at
multiple granularity levels practical, additional types of locks
locks are used. Intention locks are table-level locks in
InnoDB that indicate which type of lock
(shared or exclusive) a transaction will require later for a row
in that table. There are two types of intention locks used in
InnoDB (assume that transaction
T has requested a lock of the indicated type
The intention locking protocol is as follows:
Before a transaction can acquire an
Slock on a row in table
t, it must first acquire an
ISor stronger lock on
Before a transaction can acquire an
Xlock on a row, it must first acquire an
These rules can be conveniently summarized by means of the following lock type compatibility matrix.
A lock is granted to a requesting transaction if it is compatible with existing locks, but not if it conflicts with existing locks. A transaction waits until the conflicting existing lock is released. If a lock request conflicts with an existing lock and cannot be granted because it would cause deadlock, an error occurs.
Thus, intention locks do not block anything except full table
requests (for example,
LOCK TABLES ...
WRITE). The main purpose of
locks is to show that someone is locking a row, or going to lock
a row in the table.
A record lock is a lock on an index record. For example,
SELECT c1 FOR UPDATE FROM t WHERE c1 = 10;
prevents any other transaction from inserting, updating, or
deleting rows where the value of
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 15.8.9, “Clustered and Secondary Indexes”.
A gap lock is a lock on a gap between index records, or a lock
on the gap before the first or after the last index record. For
SELECT c1 FOR UPDATE FROM t WHERE c1 BETWEEN
10 and 20; prevents other transactions from inserting
a value of
15 into column
t.c1, whether or not there was already any
such value in the column, because the gaps between all existing
values in the range are locked.
A gap might span a single index value, multiple index values, or even be empty.
Gap locks are part of the tradeoff between performance and concurrency, and are used in some transaction isolation levels and not others.
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.
Gap locking can be disabled explicitly. This occurs if you
change the transaction isolation level to
READ COMMITTED or enable the
system variable (which is now deprecated). Under these
circumstances, gap locking is disabled for searches and index
scans and is used only for foreign-key constraint checking and
There are also other effects of using the
READ COMMITTED isolation
level or enabling
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
condition of the
A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.
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. 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.
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.
InnoDB operates in
REPEATABLE READ transaction
isolation level. In this case,
next-key locks for searches and index scans, which prevents
phantom rows (see Section 15.5.4, “Phantom Rows”).
An insert intention lock is a type of gap lock 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 are nonconflicting.
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
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 ;;...
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.
configuration option controls the algorithm used for
auto-increment locking. It allows you to choose how to trade off
between predictable sequences of auto-increment values and
maximum concurrency for insert operations.
For more information, see Section 15.8.6, “AUTO_INCREMENT Handling in InnoDB”.
As of MySQL 5.7.5,
SPATIAL indexing of columns containing
spatial columns (see
Section 126.96.36.199, “Optimizing Spatial Analysis”).
To handle locking for operations involving
SPATIAL indexes, next-key locking does not
work well to support
isolation levels. There is no absolute ordering concept in
multidimensional data, so it is not clear which is the
To enable support of isolation levels for tables with
uses predicate locks. A
contains minimum bounding rectangle (MBR) values, so
InnoDB enforces consistent read on the index
by setting a predicate lock on the MBR value used for a query.
Other transactions cannot insert or modify a row that would
match the query condition.