本节描述了 InnoDB 使用的锁类型。This section describes lock types used by
InnoDB.
InnoDB 实现了标准的行级锁,其中有两种类型的锁,共享 (S) 锁 和 排他 (X) 锁。InnoDB implements standard row-level locking
where there are two types of locks,
shared (S)
locks and exclusive
(X) locks.
共享 (
S) 锁 允许持有该锁的事务读取一行数据。A shared (S) lock permits the transaction that holds the lock to read a row.排他 (
X) 锁允许持有锁的事务更新或删除一行。An exclusive (X) lock permits the transaction that holds the lock to update or delete a row.
如果事务 T1 对行 r 持有共享 (S) 锁,那么来自某个不同事务 T2 的对行 r 的锁请求将按如下方式处理:If transaction T1 holds a shared
(S) lock on row r, then
requests from some distinct transaction T2
for a lock on row r are handled as follows:
T2对S锁的请求可以立即被授予。因此,T1和T2都对r持有S锁。A request byT2for anSlock can be granted immediately. As a result, bothT1andT2hold anSlock onr.T2对X锁的请求不能立即被授予。A request byT2for anXlock cannot be granted immediately.
如果一个事务 T1 在行 r 上持有排他锁(X),那么来自某个不同事务 T2 对 r 上任意类型锁的请求不能立即被授予。相反,事务 T2 必须等待事务 T1 释放其在行 r 上的锁。If a transaction T1 holds an exclusive
(X) lock on row r, a
request from some distinct transaction T2 for
a lock of either type on r cannot be granted
immediately. Instead, transaction T2 has to
wait for transaction T1 to release its lock
on row r.
InnoDB 支持 多粒度锁定,允许行锁和表锁共存。例如,像 LOCK TABLES ...
WRITE 这样的语句会在指定的表上获取一个排他锁(一个 X 锁)。为了使多粒度锁定变得可行,InnoDB 使用 意向锁。意向锁是表级锁,用于指示事务以后在表中的某行需要哪种类型的锁(共享锁或排他锁)。意向锁有两种类型:InnoDB supports multiple
granularity locking which permits coexistence of row
locks and table locks. For example, a statement such as
LOCK TABLES ...
WRITE takes an exclusive lock (an X
lock) on the specified table. To make locking at multiple
granularity levels practical, InnoDB uses
intention locks.
Intention locks are table-level locks that indicate which type
of lock (shared or exclusive) a transaction requires later for a
row in a table. There are two types of intention locks:
一个 意向共享锁 (
IS) 表示事务打算在表中的单个行上设置 共享 锁。An intention shared lock (IS) indicates that a transaction intends to set a shared lock on individual rows in a table.一个 意向排他锁 (
IX) 表示事务打算在表中的单个行上设置排他锁。An intention exclusive lock (IX) indicates that a transaction intends to set an exclusive lock on individual rows in a table.
例如,SELECT ...
FOR SHARE 设置一个 IS 锁,而 SELECT ... FOR
UPDATE 设置一个 IX 锁。For example, SELECT ...
FOR SHARE sets an IS lock, and
SELECT ... FOR
UPDATE sets an IX lock.
意向锁协议如下:The intention locking protocol is as follows:
在事务可以在表中的某一行上获取共享锁之前,它必须首先在该表上获取一个
IS锁或更强的锁。Before a transaction can acquire a shared lock on a row in a table, it must first acquire anISlock or stronger on the table.在事务可以在表中的某一行上获取独占锁之前,它必须首先在该表上获取一个
IX锁。Before a transaction can acquire an exclusive lock on a row in a table, it must first acquire anIXlock on the table.
表级锁类型的兼容性总结如下矩阵。Table-level lock type compatibility is summarized in the following matrix.
X |
IX |
S |
IS |
|
|---|---|---|---|---|
X |
冲突Conflict | 冲突Conflict | 冲突Conflict | 冲突Conflict |
IX |
冲突Conflict | 兼容Compatible | 冲突Conflict | 兼容Compatible |
S |
冲突Conflict | 冲突Conflict | 兼容Compatible | 兼容Compatible |
IS |
冲突Conflict | 兼容Compatible | 兼容Compatible | 兼容Compatible |
如果请求的事务与现有锁兼容,则会授予锁,但如果与现有锁冲突,则不会授予锁。事务会等待,直到冲突的现有锁被释放。如果锁请求与现有锁冲突且无法授予,因为这会导致死锁,则会发生错误。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.
意向锁不会阻塞任何操作,除了对整个表的请求(例如,LOCK
TABLES ... WRITE)。意向锁的主要目的是表示有人正在锁定行,或者将要锁定表中的某一行。Intention locks do not block anything except full table requests
(for example, LOCK
TABLES ... WRITE). The main purpose of intention locks
is to show that someone is locking a row, or going to lock a row
in the table.
意向锁的事务数据在 SHOW
ENGINE INNODB STATUS 和 InnoDB 监视器 输出中类似如下:Transaction data for an intention lock appears similar to the
following in SHOW
ENGINE INNODB STATUS and
InnoDB monitor
output:
TABLE LOCK table `test`.`t` trx id 10080 lock mode IX
记录锁是对索引记录的锁。例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; 会阻止任何其他事务插入、更新或删除 t.c1 值为 10 的行。A record lock is a lock on an index record. For example,
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
prevents any other transaction from inserting, updating, or
deleting rows where the value of t.c1 is
10.
记录锁总是锁定索引记录,即使表定义为没有索引。在这种情况下,InnoDB 会创建一个隐藏的聚簇索引,并使用该索引进行记录锁定。参见 第 17.6.2.1 节,“聚簇索引和辅助索引”。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 17.6.2.1, “Clustered and Secondary Indexes”.
记录锁的事务数据在 SHOW
ENGINE INNODB STATUS 和 InnoDB 监视器 输出中类似如下显示:Transaction data for a record lock appears similar to the
following in SHOW
ENGINE INNODB STATUS and
InnoDB monitor
output:
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` trx id 10078 lock_mode X locks rec but not gap Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 8000000a; asc ;; 1: len 6; hex 00000000274f; asc 'O;; 2: len 7; hex b60000019d0110; asc ;;
间隙锁是锁定索引记录之间的间隙,或锁定第一个索引记录之前或最后一个索引记录之后的间隙。例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20
FOR UPDATE; 会阻止其他事务向列 t.c1 插入值 15,无论该列中是否已经存在该值,因为该范围内所有已存在值之间的间隙都被锁定。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
example, SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20
FOR UPDATE; 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.
对于使用唯一索引查找唯一行而锁定行的语句,不需要间隙锁。(这不包括查询条件仅包含多列唯一索引的部分列的情况;在这种情况下,会发生间隙锁。) 例如,如果 id 列有唯一索引,以下语句仅对具有 id 值为 100 的行使用索引记录锁,无论其他会话是否在前面的间隙中插入行,都无关紧要: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:
SELECT * FROM child WHERE id = 100;
如果 id 没有索引或具有非唯一索引,则该语句确实会锁定前面的间隙。If id is not indexed or has a nonunique
index, the statement does lock the preceding gap.
这里还值得注意的是,不同的事务可以在同一个间隙上持有冲突的锁。例如,事务 A 可以在一个间隙上持有共享间隙锁(gap S-lock),而事务 B 在同一个间隙上持有独占间隙锁(gap X-lock)。允许冲突的间隙锁的原因是,如果一条记录从索引中被删除,不同事务在该记录上持有的间隙锁必须合并。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.
InnoDB 中的间隙锁是“纯粹的抑制性”,这意味着它们的唯一目的是防止其他事务向间隙中插入数据。间隙锁可以共存。一个事务持有的间隙锁不会阻止另一个事务在同一个间隙上持有间隙锁。共享间隙锁和独占间隙锁没有区别。它们彼此不冲突,并且执行相同的功能。Gap locks in InnoDB are “purely
inhibitive”, which means that their only purpose is to
prevent other transactions from inserting to the gap. Gap locks
can co-exist. A gap lock taken by one transaction does not
prevent another transaction from taking a gap lock on the same
gap. There is no difference between shared and exclusive gap
locks. They do not conflict with each other, and they perform
the same function.
间隙锁可以被显式禁用。如果您将事务隔离级别更改为 READ COMMITTED,就会发生这种情况。在这种情况下,间隙锁在搜索和索引扫描中被禁用,仅用于外键约束检查和重复键检查。Gap locking can be disabled explicitly. This occurs if you
change the transaction isolation level to
READ COMMITTED. In this case,
gap locking is disabled for searches and index scans and is used
only for foreign-key constraint checking and duplicate-key
checking.
使用READ COMMITTED隔离级别还有其他影响。对于不匹配的行,记录锁在 MySQL 评估完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.There are also other effects of using the
READ COMMITTED isolation
level. 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.
下一个键锁是索引记录上的记录锁和索引记录前间隙上的间隙锁的组合。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执行行级锁定的方式是,当它搜索或扫描表索引时,会对遇到的索引记录设置共享锁或独占锁。因此,行级锁实际上是索引记录锁。索引记录上的下一键锁也会影响“间隙”。也就是说,下一键锁是索引记录锁加上索引记录前间隙的间隙锁。如果一个会话在索引记录上有共享或排他锁R,另一个会话不能在索引顺序中紧接前的空白插入新的索引记录R in the index order.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.
假设一个索引包含值 10、11、13 和 20。该索引的可能下一个键锁覆盖以下区间,其中圆括号表示区间端点不包含在内,方括号表示包含端点: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 在 REPEATABLE READ 事务隔离级别下运行。在这种情况下,InnoDB 对搜索和索引扫描使用 next-key 锁,这防止了幻影行(参见 第 17.7.4 节,“幻影行”)。By default, InnoDB operates in
REPEATABLE READ transaction
isolation level. In this case, InnoDB uses
next-key locks for searches and index scans, which prevents
phantom rows (see Section 17.7.4, “Phantom Rows”).
next-key 锁的事务数据在 SHOW
ENGINE INNODB STATUS 以及 InnoDB 监控器 输出中显示类似如下:Transaction data for a next-key lock appears similar to the
following in SHOW
ENGINE INNODB STATUS and
InnoDB monitor
output:
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` trx id 10080 lock_mode X Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 8000000a; asc ;; 1: len 6; hex 00000000274f; asc 'O;; 2: len 7; hex b60000019d0110; asc ;;
插入意图锁是一种由INSERT操作在行插入之前设置的间隙锁。这种锁表示插入意图,使得在同一索引间隙中插入的多个事务如果没有在间隙的相同位置插入,不必互相等待。假设索引记录的值为 4 和 7。分别尝试插入值 5 和 6 的不同事务,在获得插入行的独占锁之前,各自锁定 4 和 7 之间的间隙,但不会相互阻塞,因为行是非冲突的。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.
下面的示例演示了一个事务在获得插入记录的独占锁之前取得插入意图锁。示例涉及两个客户端,A 和 B。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.
客户端 A 创建一个包含两个索引记录(90 和 102)的表,然后开始一个事务,对 ID 大于 100 的索引记录加上排他锁。该排他锁包括记录 102 之前的间隙锁: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:
mysql>CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;mysql>INSERT INTO child (id) values (90),(102);mysql>START TRANSACTION;mysql>SELECT * FROM child WHERE id > 100 FOR UPDATE;+-----+ | id | +-----+ | 102 | +-----+
客户端 B 开始一个事务,将记录插入间隙。在等待获得排他锁时,该事务会获取一个插入意向锁。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.
mysql>START TRANSACTION;mysql>INSERT INTO child (id) VALUES (101);
插入意向锁的事务数据在 SHOW ENGINE INNODB
STATUS 和 InnoDB 监视器 输出中类似如下所示:Transaction data for an insert intention lock appears similar to
the following in
SHOW ENGINE INNODB
STATUS and
InnoDB monitor
output:
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 锁是一种特殊的表级锁,由在具有 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.
innodb_autoinc_lock_mode 变量控制用于自增锁定的算法。它允许你选择如何在自增值的可预测序列和插入操作的最大并发性之间进行权衡。The innodb_autoinc_lock_mode
variable 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.
有关更多信息,请参见 第 17.6.1.6 节,“InnoDB 中的 AUTO_INCREMENT 处理”。For more information, see Section 17.6.1.6, “AUTO_INCREMENT Handling in InnoDB”.
InnoDB 支持对包含空间数据的列进行 SPATIAL 索引(参见 第 13.4.9 节,“优化空间分析”)。InnoDB supports SPATIAL
indexing of columns containing spatial data (see
Section 13.4.9, “Optimizing Spatial Analysis”).
为了处理涉及 SPATIAL 索引的操作的锁定,下一键锁定在支持 REPEATABLE
READ 或 SERIALIZABLE 事务隔离级别时效果不佳。多维数据中不存在绝对的顺序概念,因此不清楚哪个是 “下一个” 键。To handle locking for operations involving
SPATIAL indexes, next-key locking does not
work well to support REPEATABLE
READ or
SERIALIZABLE transaction
isolation levels. There is no absolute ordering concept in
multidimensional data, so it is not clear which is the
“next” key.
为了支持具有 SPATIAL 索引的表的隔离级别,InnoDB 使用谓词锁。SPATIAL 索引包含最小外接矩形(MBR)值,因此 InnoDB 通过在用于查询的 MBR 值上设置谓词锁来强制索引上的一致性读取。其他事务无法插入或修改会匹配查询条件的行。To enable support of isolation levels for tables with
SPATIAL indexes, InnoDB
uses predicate locks. A SPATIAL index
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.