原文链接 https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-shared-exclusive-locks
InnoDB锁分类
- Shared and Exclusive Locks (共享锁和独占锁)
- Intention Locks (意向锁)
- Record Locks(行锁)
- Gap Locks(间隙锁)
- Next-key Locks()
- Insert Intention Locks(插入意向锁)
- AUTO-INC Locks()
- Predicate Locks for Spatial Indexes
Shared and exclusive Locks(共享锁和独占锁)
InnoDB implementts standard row-level locking where there are two types of locks, shared(s) locks and exclusive(X) locks. (InnoDB实现了共享锁和独占锁两种标准行级别的锁)
- A shared (S) lock permits the transaction that holds the lock to read a row. (共享锁允许事务持有读一行数据的锁)
- An exclusive (X) lock permits the transaction that holds the lock up update or delete a row. (独占锁允许事务持有更新或删除一行数据的锁)
If transaction T1 hold a shared (s) locl on row r, then requests from some distinct transaction T2 for a lock on row r are handled as follows; (假如事务T1持有r行的共享锁),然后另一个T2事务同样请求来获取r行的锁,处理如下:
- A request by T2 for an s lock can be granted immediately. As a result, both T1 and T2 hold on S lock on r ( T2事务请求获取S锁,可以马上获得。这时候T1和T2两个事务同时持有r的S锁)
- A request by T2 for an X lock cannot be granted immeditely. (T2事务请求获取X锁不会马上授权)
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 immeditely. Instead, transaction T2 has to wait for transaction T1 to release its lock on row r. (如果T1事务持有了r行的X锁,T2事务再请求获取r行的锁不会马上获得,反而,T2事务必须等待T1事务释放锁才可以获取r行的锁)
Intention Locks (意向锁)
InnoDB supports multiple granularity locking which permits coexistence of row locks and table locks. For example, a statement such as LOCK TABLE ... WRITE takes an exclusive lock (an X lock) on the specified table. To make locking at mutiple granularity levels pratical, InnoDB uses intention locks. 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:
(InnoDB 支持多种粒度的锁以及行和表的重入锁). 例如,语句 LOCK TALBES ... WRITE 获取一个表的独占锁。 为了使多粒度级别的锁可以使用, InnoDB 使用意向锁. 意向锁是表级别的锁, 表示在一个表中执行事务可以通过获取不同类型的锁(共享锁和独占锁). 两种意向所如下:
- An intention shared lock (IS) indicates that a transaction intends to set a shared lock on individual rows in a table. (意向锁表示事务可以通过设置一个共享锁来持有表中的指定行)
- An intention exclusive lock (IX) indicates that a transaction intends to set an exclusive lock on individual rows in table. (意向独占锁表示事务可以通过一个独占锁来持有表中的行)
For example, SELECT ... FOR SHARE sets an IS lock, and SELECT ... FOR UPDATE sets an IX lock. (例如,SELECT ... FOR SHARE 设置一个IS锁, SELECT ... FOR UPDATE 设置一个独占锁)
The intention locking protocol is as follows: (意向锁协议如下)
- Before a transaction can acquire a shared lock on a row in a table, it must first acquire an IS lock or stronger on the table. (在事务获取一个表的共享锁之前,必须首先获取一个IS锁或更高级别的锁)
- Before a transaction can aquire an exclusive lock on a row in a table, it must first acquire an IX on the tables. (在事务获取一个表的独占锁之前,必须首先获取一个IX锁或者更高级别的锁)
Table-level lock type compatibility is summarized in the following maxtrix. (表级别的锁类型的兼容性总结如下表格)
X(独占锁) | IX(意向独占锁) | S(共享锁) | IS(意向共享锁) | |
---|---|---|---|---|
X(独占锁) | Confict(不兼容) | Confict(不兼容) | Confict(不兼容) | Confict(不兼容) |
IX(意向独占锁) | Confict(不兼容) | Compatible(兼容) | Confict(不兼容) | Compatible(兼容) |
S(共享锁) | Confict(不兼容) | Confict(不兼容) | Compatible(兼容) | Compatible(兼容) |
IS(意向共享锁) | Confict(不兼容) | Compatible(兼容) | Compatible(兼容) | Compatible(兼容) |
A lock is granted to a requesting transaction if it is compatible, but not if it conflicts with exisint locks. A transaction waits until the conflicting exsiting lock is released. If a lock request conflicts with an existing lock and cannot be granted because it would cause deadlock, an error occurs. (如果已经存在一个兼容性的锁,那么请求事务是可以再次获取锁的,但是不是独占锁.事务必须等到持有的独占锁释放.如果一个事务请求获取一个已经存在独占锁的数据但是无法授权就会导致死锁,出现错误.)
Intention locks do not block anything except full table requests (for example, LOCK TABLES ... WRITE). The main purpose of intention locks is show that someone is locking a row, or going to lock a row in the table. (除了全表请求(例如, LOCK TABLES ... WRITE),意向锁不会阻塞任何请求. 意向锁的主要目的是表明有人正在锁定一行数据,或则正在锁定表中的一行数据.)
Transaction data for an intention lock appears similar to the following in SHOW ENGINE INNODB STATUS and InnoDB monitor output: (意向锁的事务数据在 SHOW ENGINE STATUS 和 InnoDB monitor的输出如下:)
TABLE LOCK tales `test`.`t` trx id 10080 lock mode IX
Record locks
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. (行锁是基于索引的。例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;防止其它事务的插入,修改或则删除t.c1=10的行数据。)
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.6.2.1,"Clustered and Secondary Indexes". (行锁只会锁住带有索引的行,即使表没有定义索引。这种情况,InnoDB会创建一个隐藏的clustered索引来使用给行锁使用。见章节 15.6.2.1,“聚簇索引和二级索引”)
Transaction data for a record lock appears similar to the the following is SHOW ENGINE INNODB STATUS and InnoDB monitor output (使用行锁的事务数据通过 SHOW ENGINE INNODB 和 InnoDB monitor 看起来想下面的输出):
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
o: len 4; hex 800000a; asc ;;
1: len 6; hex 00000000274f; asc '0;;
2: len 7; hex b60000019d0110; asc ;;
Gap Locks (间隙锁)
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. (间隙锁是锁住一个范围的索引,或者锁住第一条数据之前的数据,或者最后一条数据之后的数据。例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;防止其它事务再t.c1上插入一条15的值,无论该列是否已经存在任何这样的值,因为该范围内的值都被锁上了间隙锁)
A gap might span a single index value, multiple index values, or even empty. (间隙锁可能包括单个索引值,多个索引值,或者甚至为空)
Gap locks are part of hte tradeoff between performance and concurrency, and are used in some transaction isolation levels and not others. (间隙锁是性能和并发权衡的一部分,并且用于一些事务的隔离级别而不是其它级别)
Gap locking is not needed for statement 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 id does not matter whether other sessions insert rows in the perceding gap: (使用唯一索引搜索唯一行语句不需要使用间隙锁定,(这不包括搜索条件只包含多列唯一索引的部分列的情况,这中情况,会出现间隙锁)例如,如果id列是唯一索引,以下语句仅对id为100的行使用index-record lock,其它的会话是否在前面的间隙中插入间隙锁都没有关系)
SELECT * FROM child WHERE id = 100;
If id is not indexed or has nonunique index, the statement does lock the preceding gap. (如果没有index或则唯一索引,就会锁定前面的数据)
If is also worth noting hear 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持有了间隙共享锁 gap S-lock在一个间隙中,事务B持有了一个独占间隙锁 gap X-lock也在同样的间隙上,如果清除了记录的索引,间隙锁冲突是允许的,不同的事务在记录上持有的间隙锁必须合并)
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. The do not conflict with each other, and they perform the same function. (间隙锁在InnoDB是"purely inhibitive",意味着它们的作用是防止其它事务在间隙锁范围插入数据。 间隙锁可以共存。一个事务使用了间隙锁不会组织其它事务在同一个间隙锁再次使用间隙锁。共享和独占间隙锁没有区别。它们不会互相冲突,而且他们的功能一样)
Gap locking can be disable explicitly. This occurs if you change the transaction isolation level to READ COMMITTED. In this case, gap locking is disabled fo searches and index scans and is used only for foreign-key constraint checking and duplicate-key checking. (间隙锁可以明确关闭,如果你调整事务隔离级别为 READ COMMITTED。这种情况,在搜索和索引扫描用于外键约束和重复键约束间隙锁会失效)
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 conditions of the UPDATE. (只影响 READ COMMITTED的隔离级别。MySQL会评估 WHERE条件后的数据,再释放不匹配的行锁。对于UPDATE语句, InnoDB会使用 "semi-consistent" read,MySQL将返回最新提交的版本,以便MySQL可以确定该行是否满足更新的条件)
Next-Key Locks ()
A next-key locks is a combination of a record lock on the index record and a gap lock on the gap before the index record. (next-key锁是由index行的行锁和在index行之前的间隙锁组合的)
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 sessionn 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 inthe index order. (InnoDB执行行级别的锁是通过对表中索引的搜索和扫描,它在找到的记录上设置共享锁或者独占锁。因此,行锁实际上是index行锁。 next-key锁在index记录上也会影响在间隙之前的index记录。也就是说,next-key lock是一个index行锁加间隙锁,在间隙锁之前的index记录。如果一个会话存在一个共享锁或则独占锁在index的R行,其它会话不能插入新的index记录在间隙中R之前的排序好的index中)
Suppose that an idnex 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 s square bracket denotes inclusion of the endpoint: (假设一个索引包含值10,11,13,20。next-key锁尽可能的覆盖以下的间隔,一个括号表示不包含间隔节点,中括号表示包含间隔节点)
(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锁住间隙最大值以上的索引,并且“supremum"伪记录的值大于索引中的任何值, supremum(至高无上)不是一个实际的索引记录,所以,实际上,next-key锁只会锁住间隙中最大的索引值)
By defualt, 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 15.7.4,"phantom Rows"). (默认,InnoDB使用REPEATABLE READ事务隔离级别,这种情况, InnoDB使用next-lock锁搜索和索引扫描,防止幻读,(见章节 15.7.4, “幻读行”))
Transaction data for a next-key lock appears similar to the following in SHOW ENGINE INNODB STATUS and InnoDB monitor output: (next-key锁持有的事务数据通过 SHOW ENGINE INNODB STATUS和InnoDB monitor输出如下)
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 on 2 PHYSICAL RECORD: n_field 3; compact format; info bits 0
0: len 4; hex 8000000a; asc ;;
1: len 6; hex 0000000274f; asc '0;;
2: len 7; hex b60000029d0110; asc ;;
Insert Intention Locks (插入意向锁)
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 he 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 nonconfliting. (插入意向锁是只用在INSERT操作之前的的间隙锁。此锁表示插入意向,在多个事务插入在同一个索引间隙的不同位置的时候不需要等待,假设行锁的位置是4和7。其它的事务尝试分别插入值5和6,在4到7之间的间隙锁范围内,插入行时意向锁比独占锁优先获取,应为行没有冲突每个事务就不会阻塞)
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和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: (客户端A创建一个表包含两个索引记录90和20,然后开启事务使用独占锁查询id大于100的索引记录,这个独占锁包括了一个在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 TRANSACIONT;
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. (客户端B开启事务,在间隙插入一条记录,事务获取到插入意向锁后开始等待直到获取到独占锁)
mysql> START TRANSACTION;
mysql> INSERT INTO child (id) values (101);
Transaction data for an insert intention lock appears similar to the following in SHOW ENGINE INNODB STATUS and InnoDB monitor output: (插入意向锁的事务数据在 SHOW ENGINE INNODB STATUS 和 InnoDB 监视器输出中显示类似于以下内容:)
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 Locks ()
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. (AUTO-INC锁是一个特殊的表级别的锁,在通过事务插入数据到表中的AUTO_INCREMENT列使用。在最简单的情况下,如果一个事务在表中插入数据,其它事务必须等待表中的插入完成,以便第一个事务插入的行接收连续的主键值)
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. (innodb_autoinc_lock_mode变量控制auto-increment 锁的算法,它允许你选择如何在可预测连续的自动增量和插入的最大并发之间进行权衡)
For more infomation, see Seciont 15.6.1.6, "AUTO_INCREMENT Handing in InnoDB".
Predicate Locks for Spatial Indexes (空间索引的Predicate锁)
InnoDB supports SPATIAL indexing of columns containing spatial data (see Section 11.4.9, "Optimizing Spatial Analysis"). (InnoDB支持空间索引包含空间数据,见章节 11.4.9 "空间分析优化")
To handle locking for operations invoving SPATIAL indexes, next-key locking does not work well to support REPEATABLE READ or SERILIZABLE transaction isolation level. There is no absolute ordering concept in multidimensional data, so it is not clear which is the "next" key. (处理涉及到空间索引的操作,next-key锁在REPEATABLE READ或则SERIALIZABLE的事务隔离级别效果不是很好,多维数据中没有绝对排序的概念,所以无法确认下一个键)
To enable support of isolation levels for tables with SPATIAL indexs, 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 MBR value used for a query. Other transactions cannot insert or modify a row that would match the query condition. (为了确保事务级别支持空间索引,InnoDB使用predicate锁,空间索引包含最小多边矩形的值,这样InnoDB强制在空间索引上通过predicate锁来执行查询空间数据。其它事务不能插入或修改符合查询条件的行)