Detailed explanation of mysql lock

      The default storage engine of Mysql is InnoDB, so the implementation of various locks under InnoDB is mainly discussed here. In java, in order to support effective access to shared resources by multiple threads, java provides us with lightweight locks, heavyweight locks, biased locks, etc. Similarly, InnoDB provides us with a large number of lock mechanisms in order to control concurrent access. These locks can be divided into different levels: table locks, row locks, optimistic locks, pessimistic locks, shared locks, exclusive locks, intent locks, record locks, gap locks, next-key locks, etc.

     InnoDB provides two row-level lock implementations: shared locks (S locks) and exclusive locks (X locks) . The shared lock allows the transaction to hold the lock to access the locked row data. If other transactions need to access the row of the record to which the shared lock is added, they will also add and only add a shared lock to this record; To update or delete a record, an exclusive lock will be added to the row of data. At this time, it must be ensured that there is no other shared lock on the changed row data, otherwise the data read by the transaction holding the shared lock will be inconsistent. An exclusive lock is also known as an exclusive lock. During the lock holding period, other transactions can neither access nor modify the row of data.

     We can practice shared locks and exclusive locks. The last blog post mentioned that InnoDB provides multi-version concurrent access control, namely MVCC, in order to support concurrent access. A 'snapshot' of the records of all committed transactions), this is also known as no locking read, because historical data is read, it is impossible to read inconsistently, and there is no need to worry about other transactions on the data Modifications are made, so locking is not performed. To read the data of the current database for locking demonstration, we can use select ... lock in share mode and select ... for update, the former will add a shared lock to a row record in the current database read, and then or plus an exclusive lock. (In fact, an intention lock will be added here).

as follows:


      When the B operation is performed, the transaction in session 2 will add an exclusive lock to the record (2, 3). Due to MVCC, the historical data is read by the A operation, so the transaction in session 1 will not hold the record (2, 3). ,3) on the shared lock, at this time session 2 is successfully locked.


Here, because operation A reads the data in the latest database, in order to ensure the consistency of reading data, session 1 will add a shared lock to (2,3), and operation B will block until ( 2,3) on the lock release. As we said earlier, select ... lock in share mode and select ... for update are not simply adding S locks and X locks to a row record, but actually adding a table to the table where the record is located. level intent lock, the details are as follows:

                    Intentional shared lock : The lock will now or later have a transaction add a shared lock to a row in the table.

                    Intentional exclusive lock : The lock will now or later have a transaction add an exclusive lock to a row in the table.

 Why is another table-level intent lock designed here? In short, intent locks can roughly be thought of as 'sentinels'. For example, transaction T1 now holds the shared lock of record (1,1) on table a. At this time, transaction T2 executes the alter operation. In order to execute successfully, it must be determined that there is no lock on each row of data in table a. At this time, if a row Row checking, once there are more records in the table, the time spent checking the lock will be huge. In order to avoid this time-consuming operation, you only need to check whether there is an intentional lock on table a. If not, transaction T2 is successfully executed. If it exists, it indicates that a record in table a is being used, and transaction T2 will Block until the intent lock is removed, which greatly reduces the judgment time.

     It must be clear here that locking a row record mentioned above is actually locking the record on the clustered index. If the query condition is based on the secondary index, then the record on the secondary index will be compared with the second record. The record on the clustered index of the primary key pointed to by the level index is locked. If the query condition does not have any index, a full table scan will be performed, and the records on the clustered index corresponding to each row of data in the table will be added. lock, which is a bad situation and means that no other transaction can do much with the table. This leads to record locks, that is, record locks.

      record lock : The shared locks and exclusive locks mentioned above actually belong to the records, that is, the locks added to the records on the index. For example: select * from test where number=2 for update (where the index on number is a secondary index) will cluster the record with the key value of 2 on the secondary index corresponding to number and the primary key pointed to by the index Records on the index plus X locks. Some people may think that it is only necessary to add X locks to the records corresponding to 2 on this secondary index. Why do you need to add X locks to the records on the clustered index of the primary key? We might as well assume such a situation. If the table has multiple columns, id is the primary key, and there are secondary indexes on the number column and other columns, if a record of the secondary index of other columns (assuming the column name is name) happens to be The record with a value of 2 on the number index points to the same primary key. Since the record on the clustered index corresponding to the primary key is not locked at this time, we update this data according to the name column, which will cause dirty reads .

      Most of the locks have been introduced. These locks only lock a certain record or table. The rational use of these locks can solve the problem of dirty reads and non-repeatable reads, but there is one last problem, phantom reads. Phantom read means that a transaction inserts a record in a certain range, resulting in inconsistency in the number of rows of data read before and after other transactions, and the extra or missing row is called a phantom row. To solve the problem of phantom reads, InnoDB uses gap locks. As the name implies, a gap lock means that what is locked is not a record but an interval. Let's first look at the following example:


        There are only three records in the test table (2, 2), (3, 3), (4, 4); when the transaction in session 1 performs the A operation, the delete statement is the current read (delete, update, and insert have internal The current read operation of a select), because in the current read state, the data is the latest, if another transaction adds a record with number=5, such as (5,5), then in the session 1 transaction, if the If you perform an operation similar to A, you will find that a new (5,5) record inserted by another transaction has been retrieved inside the execution of the delete statement. Before, this record did not exist at all. This is phantom read. Row data is also called phantom rows. In order to solve this problem, that is, to prevent other transactions from inserting records with number=5, InnoDB sets the key value on the secondary index of number to the left and right intervals of 5 (because the index is stored in a B+ tree, and the key value on the child node of the B+ tree is If other transactions want to insert a record in this interval at this time, they will always block waiting for the release of the lock. Here the key value adjacent to 5 and smaller than 5 is 4, and there is no key value adjacent to 5 and larger than 5, so the default value is positive infinity, that is to say, the interval of (4, positive infinity) is added Locks, other transactions inserting records with number values ​​in this range will block.

       The next-key lock is record lock+gap lock, the lock range is the range actually locked in the above example, and the range locked by the gap lock does not include (5,5).


      The most critical point now is to determine when the gap lock will occur. The gap lock was designed to solve the phantom reading problem from the beginning, so where there is a possibility of phantom reading, a gap lock will be added, such as:

                    select * from test where number=4 lock in share mode;

Will a gap lock be generated when this statement is executed? We know from the above that the read operation is the current read, so there must be a problem of concurrent reading and writing. There are two cases here:

       1. The index of the number column is a common index. At this time, another transaction B inserts a record with number=4 (assuming the record is (3,4)), then this statement is executed before and after transaction B executes the insert statement. The result will be inconsistent, that is to say, there will be one more matching record in the second read, which will generate a phantom read. At this time, InnoDB will put the record with key value 4 and the record on the secondary index of the number column. The gap between the left and right open intervals of 4 is locked, and on the clustered index of the primary key, the record with the key value of 4 is locked.

       2. The index of the number column is a unique index. At this time, under high concurrent access, it is still guaranteed that the result of the query will not generate a magic row, because other transactions cannot insert records with number=4

       3. The number column is not indexed. At this time, only a full table scan can be used. In order to ensure that no phantom read occurs, all records on the primary key clustered index + the gap between records will be locked. Worst case now.

Because delete, update, insert (insert is special, may trigger the conflict check of unique key, so there will also be a current read) and other operations are current read operations, so their analysis is similar to the above. In fact, it is a good judgment. If the results of the query may be different according to the current read where condition, then a next-key lock (gap lock + record lock) will be added to prevent phantom reading.

ps: In the company's project, uuid (non-primary key) is usually used as a search and update condition for writing. At the same time, the index of the uuid column is designed as a common index, resulting in gaps. InnoDB adds a lot of gap locks for these gaps. In the case of a small amount of concurrency, this is not a problem, but once the amount of concurrency increases, the uuid of the newly generated record will be blocked if it happens to be in the gap after sorting. It took us about three days to find out, and the solution is also very simple. All where conditions such as update and delete are replaced by primary keys, or the index on the uuid column is designed as a unique type.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325941966&siteId=291194637
Recommended