A locking read, an UPDATE, or a DELETE generally set record locks on every index record that is scanned in the processing of the SQL statement. It does not matter whether there are WHERE conditions in the statement that would exclude the row. InnoDB does not remember the exact WHERE condition, but only knows which index ranges were scanned. The locks are normally next-key locks that also block inserts into the “gap” immediately before the record. However, gap locking can be disabled explicitly, which causes next-key locking not to be used. For more information, see Section 14.5.1, “InnoDB Locking”. The transaction isolation level also can affect which locks are set; see Section 14.5.2.1, “Transaction Isolation Levels”.
一般来说,锁定读,updte,delete等类型的SQL语句通常在执行的过程中会对被扫描的索引记录加记录锁,这跟有没有过滤行的where条件没有关系,InnoDB 不记得确切的where条件, 但只知道扫描了哪些索引范围。,锁通常是next-ket锁, 它还会在记录之前阻止插入到 "间隙" 中。,但是,gap锁是可以手动禁用的,禁掉后也就不会用到所谓的next-key锁了,更多内容,请看Section 14.5.1, “InnoDB Locking”,事务的隔离级别也会对锁产生影响,更多信息请看Section 14.5.2.1, “Transaction Isolation Levels”.
If a secondary index is used in a search and index record locks to be set are exclusive, InnoDB also retrieves the corresponding clustered index records and sets locks on them.
如果某个查询中用到了辅助索引并且对应记录加上了排他锁,那么innodb会检索相关的聚簇索引记录,并在其上面加上锁
Differences between shared and exclusive locks are described in Section 14.5.1, “InnoDB Locking”.
有关共享锁和排他锁的差异,请看Section 14.5.1, “InnoDB Locking”.
If you have no indexes suitable for your statement and MySQL must scan the entire table to process the statement, every row of the table becomes locked, which in turn blocks all inserts by other users to the table. It is important to create good indexes so that your queries do not unnecessarily scan many rows.
如果没有适合您的语句的索引,MySQL必须扫描整个表来处理语句,,那么表的每一行都将被锁定,表的每一行都会被锁定,这反过来会阻止其他用户对表的所有插入。 创建好的索引非常重要,这样您的查询就不会不必要地扫描很多行
For SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE, locks are acquired for scanned rows, and expected to be released for rows that do not qualify for inclusion in the result set (for example, if they do not meet the criteria given in the WHERE clause). However, in some cases, rows might not be unlocked immediately because the relationship between a result row and its original source is lost during query execution. For example, in a UNION, scanned (and locked) rows from a table might be inserted into a temporary table before evaluation whether they qualify for the result set. In this circumstance, the relationship of the rows in the temporary table to the rows in the original table is lost and the latter rows are not unlocked until the end of query execution.
SELECT ... FOR UPDATE或者SELECT ... LOCK IN SHARE MODE会为扫描上的行加锁,并且会释放不在结果集中的记录的锁(例如,如果它们不符合WHERE子句中给出的条件),然而,在有些情况下,这些行上的锁不会马上被释放,因为在查询执行过程中,结果行和它的原始源之间的关系将丢失。例如,在存在union的sql中,从表中扫描 ( 和锁定 ) 的行可能插入到临时表中 , 然后再评估它们是否符合结果集的资格,在这种情况下,由于临时表中的表的行和原始表中的行的关系被丢失了,直到查询执行结束后才解锁后的行。
InnoDB sets specific types of locks as follows.
InnoDB设置锁的具体类型如下。
- SELECT ... FROM is a consistent read, reading a snapshot of the database and setting no locks unless the transaction isolation level is set to SERIALIZABLE. For SERIALIZABLE level, the search sets shared next-key locks on the index records it encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
- SELECT … FROM读的是数据库的一致性快照,一般不会加锁除非事务隔离级别是SERIALIZABLE,在SERIALIZABLE级别中,会对查询到的结果集加共享next-key锁,但是,有一种情况只会针对一行索引记录加锁,那就是语句了使用惟一索引,那么就只会查到一行
- SELECT ... FROM ... LOCK IN SHARE MODE sets shared next-key locks on all index records the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
- SELECT ... FROM ... LOCK IN SHARE MODE会针对查出来的每一行记录都加上共享next-key锁,但是,有一种情况只会针对一行索引记录加锁,那就是语句了使用惟一索引,那么就只会查到一行
- SELECT ... FROM ... FOR UPDATE sets an exclusive next-key lock on every record the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
- SELECT ... FROM ... FOR UPDATE 会针对查出来的每一行记录都加上排他next-key锁,但是,有一种情况只会针对一行索引记录加锁,那就是语句了使用惟一索引,那么就只会查到一行
- For index records the search encounters, SELECT ... FROM ... FOR UPDATE blocks other sessions from doing SELECT ... FROM ... LOCK IN SHARE MODE or from reading in certain transaction isolation levels. Consistent reads ignore any locks set on the records that exist in the read view.
- 针对查询中碰到的任何记录,SELECT ... FROM ... FOR UPDATE会阻塞其他会话正在执行的SELECT ... FROM ... LOCK IN SHARE MODE 查询语句或在某些事务隔离级别的读取,一致读取忽略设置在读视图中的记录上的任何锁。
- UPDATE ... WHERE ... sets an exclusive next-key lock on every record the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
- UPDATE ... WHERE ...会针对查出来的每一行记录都加上排他next-key锁,但是,有一种情况只会针对一行索引记录加锁,那就是语句了使用惟一索引,那么就只会查到一行
- When UPDATE modifies a clustered index record, implicit locks are taken on affected secondary index records. The UPDATE operation also takes shared locks on affected secondary index records when performing duplicate check scans prior to inserting new secondary index records, and when inserting new secondary index records.
- 当UPDATE修改了聚簇索引,那么会对受影响的辅助索引记录采取隐式锁定。在插入新的辅助索引记录和插入新的辅助索引记录之前执行重复检查扫描时,UPDATE操作还会对受影响的辅助索引记录执行共享锁。
- DELETE FROM ... WHERE ... sets an exclusive next-key lock on every record the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
- DELETE FROM ... WHERE ... 会针对查出来的每一行记录都加上排他next-key锁,但是,有一种情况只会针对一行索引记录加锁,那就是语句了使用惟一索引,那么就只会查到一行
- INSERT sets an exclusive lock on the inserted row. This lock is an index-record lock, not a next-key lock (that is, there is no gap lock) and does not prevent other sessions from inserting into the gap before the inserted row.
- INSEER会在插入的那一行加上排他锁,锁是索引记录锁,不是next-key锁(也就是说,没有间隙锁。),并且不会阻止其他会话在插入行之前插入到间隙处
- Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. 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.
- 在插入行之前,设置一种称为插入意图间隙锁的间隙锁。,此锁的意思是即使在在同一索引间隙插入多个事务时,如果它们不插入在同一位置内的间隙,则不需要等待彼此。假设有索引记录,尝试插入5和6的值的单独事务每个在插入行上获得排它锁之前使用插入意向锁来锁定4和7之间的间隔。但双方都没有阻塞,因为它们的行是不冲突的
- If a duplicate-key error occurs, a shared lock on the duplicate index record is set. This use of a shared lock can result in deadlock should there be multiple sessions trying to insert the same row if another session already has an exclusive lock. This can occur if another session deletes the row. Suppose that an InnoDB table t1 has the following structure:
- 如果发生duplicate-key的错误,那么会在重复索引记录上面会设置一个共享锁,如果别的会话已经持有排他锁,而多个事务均在尝试插入同一行数据,那么使用共享锁可能会导致死锁的发生,如果别的会话想删除这些行的话,也会发生死锁,假设有如下结构的innodb表t1
- Now suppose that three sessions perform the following operations in order:
- 现在假设有3个会话按顺序执行下面的操作
- The first operation by session 1 acquires an exclusive lock for the row. The operations by sessions 2 and 3 both result in a duplicate-key error and they both request a shared lock for the row. When session 1 rolls back, it releases its exclusive lock on the row and the queued shared lock requests for sessions 2 and 3 are granted. At this point, sessions 2 and 3 deadlock: Neither can acquire an exclusive lock for the row because of the shared lock held by the other.
- session1的第一个操作会获得这一行的排他锁,session2和session3的操作都会导致duplicate-key问题,并且它们都请求该行的共享锁,当session1回滚的时候,它释放了行上的排他锁并且session2和session3都获得了共享锁队列的授权,这个时候,session2和session3发生死锁了,因为共享锁被互相持有,因此两者都不能获得排他锁
- A similar situation occurs if the table already contains a row with key value 1 and three sessions perform the following operations in order:
- 如果表里已经有1的记录额了,按下面的顺序操作的话也会发生同样的情况
- The first operation by session 1 acquires an exclusive lock for the row. The operations by sessions 2 and 3 both result in a duplicate-key error and they both request a shared lock for the row. When session 1 commits, it releases its exclusive lock on the row and the queued shared lock requests for sessions 2 and 3 are granted. At this point, sessions 2 and 3 deadlock: Neither can acquire an exclusive lock for the row because of the shared lock held by the other.
- session1的第一个操作会获得这一行的排他锁,session2和session3的操作都会导致主键重复的问题,并且它们都请求行的共享锁,当session1回滚的时候,它释放了行上的排他锁并且session2和session3都获得了共享锁队列的授权,这个时候,session2和session3发生死锁了,因为共享锁被互相持有,因此两者都不能获得排他锁
- INSERT ... ON DUPLICATE KEY UPDATE differs from a simple INSERT in that an exclusive lock rather than a shared lock is placed on the row to be updated when a duplicate-key error occurs. An exclusive index-record lock is taken for a duplicate primary key value. An exclusive next-key lock is taken for a duplicate unique key value.
- INSERT ... ON DUPLICATE KEY UPDATE不同于普通的INSERT,当发生duplicate-key错误的时候,它会在更新的行上加一个排他锁而不是共享锁,对重复主键值使用排他索引记录锁。为重复唯一键值使用排他next-key锁
- REPLACE is done like an INSERT if there is no collision on a unique key. Otherwise, an exclusive next-key lock is placed on the row to be replaced.
- 如果在一个唯一索引上没有冲突,REPLACE和INSERT一样,否则的话,它就会在被替换的行上加一个排他next-key锁
- INSERT INTO T SELECT ... FROM S WHERE ... sets an exclusive index record lock (without a gap lock) on each row inserted into T. If the transaction isolation level is READ COMMITTED, or innodb_locks_unsafe_for_binlog is enabled and the transaction isolation level is not SERIALIZABLE, InnoDB does the search on S as a consistent read (no locks). Otherwise, InnoDB sets shared next-key locks on rows from S. InnoDB has to set locks in the latter case: In roll-forward recovery from a backup, every SQL statement must be executed in exactly the same way it was done originally.
- INSERT INTO T SELECT ... FROM S WHERE ..在插入到T中的每一行上设置排他索引记录锁定(没有间隙锁定),如果事务级别是 READ COMMITTED,或者开启innodb_locks_unsafe_for_binlog并且事务级别不是SERIALIZABLE, innodb会以会以一致读的方式去查询S表(非锁定读),否则的话,innodb会在S表行上加共享next-key锁,InnoDB必须在后一种情况下设置锁:在从备份中前滚恢复时,必须按照原来的方式执行每个SQL语句。
- CREATE TABLE ... SELECT ... performs the SELECT with shared next-key locks or as a consistent read, as forINSERT ... SELECT.
- CREATE TABLE ... SELECT ...使用共享的next-key锁或作为一致读执行SELECT,跟INSERT ... SELECT.一样
- When a SELECT is used in the constructs REPLACE INTO t SELECT ... FROM s WHERE ... or UPDATE t ... WHERE col IN (SELECT ... FROM s ...), InnoDB sets shared next-key locks on rows from table s.
- 用SELECT语句用来构建像REPLACE INTO t SELECT ... FROM s WHERE …或者UPDATE t ... WHERE col IN (SELECT ... FROM s …)语句的时候,innodb会在s表上加共享的next-key锁
- While initializing a previously specified AUTO_INCREMENT column on a table, InnoDB sets an exclusive lock on the end of the index associated with the AUTO_INCREMENT column. In accessing the auto-increment counter, InnoDB uses a specific AUTO-INC table lock mode where the lock lasts only to the end of the current SQL statement, not to the end of the entire transaction. Other sessions cannot insert into the table while the AUTO-INC table lock is held; see Section 14.5.2, “InnoDB Transaction Model”.
- 在初始化一个表的先前指定的AUTO_INCREMENT列的同时,InnoDB在与AUTO_INCREMENT列关联的索引末尾设置排它锁,在访问自动增长计数列的时候,innodb会采用一个特定的AUTO-INC 表锁模式,只会锁定到当前sql语句末尾,而不是整个事务的结束,当持有AUTO-INC表锁的时候,别的会话就不能向该表中插入记录,更多信息,请看Section 14.5.2, “InnoDB Transaction Model”.
- InnoDB fetches the value of a previously initialized AUTO_INCREMENT column without setting any locks.
- InnoDB获取先前初始化的AUTO_INCREMENT列的值,而不设置任何锁。
- If a FOREIGN KEY constraint is defined on a table, any insert, update, or delete that requires the constraint condition to be checked sets shared record-level locks on the records that it looks at to check the constraint. InnoDB also sets these locks in the case where the constraint fails.
- 如果在表上定义了一个FOREIGN KEY约束,,任何需要检查约束条件的insert,update或delete都会在它查看的记录上设置共享记录级锁定以检查约束。 InnoDB还在约束失败的情况下设置这些锁。
- LOCK TABLES sets table locks, but it is the higher MySQL layer above the InnoDB layer that sets these locks. InnoDB is aware of table locks if innodb_table_locks = 1 (the default) and autocommit = 0, and the MySQL layer above InnoDB knows about row-level locks.
- LOCK TABLES设置表锁,但是设置这些锁的是InnoDB层之上的更高的MySQL层,如果在设置了 innodb_table_locks = 1和 autocommit = 0的情况下,InnoDB可以意识到表锁并且InnoDB上面的MySQL层也能知道行级锁。
- Otherwise, InnoDB's automatic deadlock detection cannot detect deadlocks where such table locks are involved. Also, because in this case the higher MySQL layer does not know about row-level locks, it is possible to get a table lock on a table where another session currently has row-level locks. However, this does not endanger transaction integrity, as discussed in Section 14.5.5.2, “Deadlock Detection and Rollback”. See also Section 14.8.1.7, “Limits on InnoDB Tables”.
- 否则,InnoDB的自动死锁检测无法检测到涉及此类表锁的死锁。,另外,因为在这种情况下,较高的MySQL层不知道行级锁,所以可以在另一个会话当前具有行级锁的表上获取表锁。但是,正如所讨论的,这不会危及事务的完整性,更多信息请看Section 14.5.5.2, “Deadlock Detection and Rollback”和 Section 14.8.1.7, “Limits on InnoDB Tables”.
PREV:14.5.2.4 Locking Reads https://blog.51cto.com/itzhoujun/2354207
NEXT: 14.5.4 Phantom Rows https://blog.51cto.com/itzhoujun/2354219