Original: http://dev.mysql.com/doc/refman/5.5/en/innodb-next-key-locking.html
14.5.2.5 avoiding the Phantom problem Using Next-key Locking
The so-called Phantom problem occurs within a transaction when the same query produces different sets of rows at Different times. For example, if a are SELECT
executed twice, but returns a row the second time that was not returned the first time, the row is a "phantom" row.
Suppose that there is a index on the column of the table and so id
want to read and lock all rows from the child
Table has a identifier value larger than, with the intention of updating some column in the selected rows later:
SELECT * from child WHERE ID > + for UPDATE;
The query scans the index starting from the first record, where is id
bigger than 100. Let the table contain rows
Having id
values of 102. If the locks set on the index records in the scanned range does not lock out inserts made in the gaps Between and 102), another session can insert a new row into the table with an id
of 101. If you were to execute the same select
within the same transaction, you would see a new row W ith an id
of 101 (a " Phantom ") in the result set returned by the query. If We regard a set of rows as a data item, the new Phantom child would violate the isolation principle of transactions tha T a transaction should is able to run so, the data it has read does don't change during the transaction.
To prevent Phantoms, innodb
uses an algorithm called next-key Locking that combines index-row locking with gap locking. innodb
performs row-level locking in such a-on-it-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 is actually index-record locks. In addition, a next-key lock on an index record also affects the "gap" before that Index record. That's, 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.
When InnoDB
scans a index, it can also lock the gap after the last record in the index. Just that happens in the preceding example:to prevent all insert into the table where id
would be bigger than Locks set by InnoDB
include a lock on the gap following id
value 102.
You can use Next-key locking to implement a uniqueness check in your application:if you read your data in share mode and Do not see a duplicate for a row you is going to inserts, then can safely inserts your row and know that the Next-key l Ock set on the successor of your row during the read prevents anyone meanwhile inserting a duplicate for your row. Thus, the Next-key locking enables the "lock" the nonexistence of something in your table.
Gap locking can disabled as discussed in section 14.5.2.4, "InnoDB Record, Gap, and Next-key Locks". This could cause phantom problems because other sessions can insert new rows to the gaps when gap locking is disabled.
14.5.2.4 InnoDB Record, Gap, and Next-key Locks
InnoDB
has several types of record-level locks including record locks, Gap locks, and next-key locks. For information about GKFX locks, exclusive locks, and intention locks, see section 14.5.2.1, "InnoDB Lock Modes".
Record Lock:this is a lock in 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 rec Ord.
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 Recor D.
Record Locks
Record locks always lock index records, even if a table was defined with no indexes. For such cases, InnoDB
creates a hidden clustered index and uses this index for record locking. See section 14.5.6.2, "Clustered and secondary Indexes".
Next-key Locks
By default, innodb
operates in repeatable READ
Transaction isolation level and with the innodb_locks_unsafe_for_binlog
system variable Disabled. innodb
uses Next-key locks for searches and index scans, which prevents Phantom Rows (see section 14.5.2.5, "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-on-it-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 is actually index-record locks. In addition, a next-key lock on an index record also affects the "gap" before that Index record. That's, 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, one, one, and 20. The possible Next-key locks for this index cover the following intervals, where (
or denote exclusion of the )
int Erval endpoint and [
or ]
denote inclusion of the endpoint:
(negative infinity, 10] (10, 11] (11, 13] (13, 20] (Positive Infinity)
For the last interval, the Next-key lock locks the gap above the largest value in the index and the "supremum" pse Udo-record has a value higher than any value actually in the index. The supremum is isn't a real index record, so, in effect, this next-key lock locks only the gap following the largest index Value.
Gap Locks
The Next-key locking example in the previous sections shows that a gap might span a single index value multiple index Valu ES, or even be empty.
Gap locking is not needed for statements, that's lock rows using a unique index to search for a unique row. (This does does include the case, the search condition includes only some columns of a multiple-column unique index; That case, gap locking does occur.) For example, if the id
column have a unique index, the following statement uses only a index-record lock for the row ha Ving Tsun id
value and it does not matter whether other sessions insert rows in the preceding gap:
SELECT * FROM child WHERE id = 100;
If id
is isn't indexed or has a nonunique index, the statement does lock the preceding gap.
A type of gap lock called an insert intention gap lock are set by insert
operations prior T o row insertion. This lock signals the intent to insert in such a-to-multiple transactions inserting into the same index gap need not Wait for each of the other if they is not inserting at the same position within the gap. Suppose that there is index records with values of 4 and 7. Separate transactions that attempt to inserts values of 5 and 6 each lock the gap between 4 and 7 with insert intention Loc KS prior to obtaining the exclusive lock in the inserted row, but does not block each other because the rows is nonconflict ing.
It is also worth noting this 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 Loc K (Gap X-lock) on the same gap. The reason conflicting gap locks is allowed was that if a record was purged from an index, the gap locks held on the record By different transactions must is merged.
Gap locks InnoDB
in is "purely inhibitive", which means they only stop other transactions from inserting to the GA P. Thus, a gap X-lock has the same effect as a gap s-lock.
disabling Gap Locking
Gap locking can be disabled explicitly. This occurs if you change the transaction isolation level to read COMMITTED
or enable the innodb_locks_unsafe_for_binlog system variable. Under these circumstances, Gap locking is disabled for searches and index scans and are used only for Foreign-key constrain t checking and duplicate-key checking.
There is also other effects of a using the READ COMMITTED
isolation level or enabling innodb_locks_unsafe_for_binlog
: Record locks for nonmatching rows is R Eleased after MySQL has evaluated the WHERE
condition. UPDATE
for statements, InnoDB
does a "semi-consistent" read, such. It returns the latest committed version to My SQL So, MySQL can determine whether the row matches the WHERE
condition UPDATE
of the.
Turn MySQL Next-key Locking