1. InnoDB locking mechanismThe InnoDB storage engine supports row-level locks and transaction processing. A transaction is a logical processing unit consisting of a group of SQL statements. Its ACID characteristics are as follows:
Concurrent transactions can improve the utilization of database resources and increase the transaction throughput of the database, but concurrent transactions also have some problems, mainly including:
"Update loss" in database concurrency should usually be completely avoided, but preventing update data loss cannot be solved by database transaction control alone. The application needs to add necessary locks to the data to be updated. The above database problems must be solved by the database providing a certain transaction isolation mechanism. In order to avoid problems caused by concurrent database transactions, four transaction isolation levels are defined in the standard SQL specification. Different isolation levels handle transactions differently. Comparison of database isolation levels
The InnoDB storage engine implements four types of row locks: shared lock (S), exclusive lock (X), intention shared lock (IS), and intention exclusive lock (IX).
Understanding Intention LocksIntention locks do not conflict with row-level S and X locks, but only with table-level S and X locks. Intention lock is to avoid traversing all row locks Consider this example: Transaction A locks a row in the table, making it readable but not writable. Afterwards, transaction B applies for a write lock for the entire table. If transaction B succeeds, then in theory it can modify any row in the table, which conflicts with the row lock held by A. The database needs to avoid this conflict, which means that B's application must be blocked until A releases the row lock. How does the database determine this conflict? Step 1: Determine whether the table has been locked by other transactions Step 2: Determine whether each row in the table is locked by a row lock. Note step 2. This judgment method is not very efficient because it requires traversing the entire table. So there is intention lock. When an intention lock exists, transaction A must first apply for an intention shared lock on the table, and then apply for a row lock on a row if successful. In the case of intention lock, the above judgment can be changed to step1: unchanged Step 2: It is found that there is an intentional shared lock on the table, which means that some rows in the table are locked by shared row locks. Therefore, transaction B's application for a write lock on the table will be blocked. 1.1 Retrieve data through index, apply shared lock, row lock (if not through index, table lock will be used) 1.1 Retrieve data through index, set shared lock and row lock SessionA SessionB mysql> set autocommit=0; mysql> set autocommit=0; Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql> select * from test; mysql> select * from test; -------------------------------------------------------------------------------- +----+-------+-------+-------+ +----+-------+-------+-------+ | id | name | money | level | | id | name | money | level | +----+-------+-------+-------+ +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 | +----+-------+-------+-------+ +----+-------+-------+-------+ 3 rows in set (0.00 sec) 3 rows in set (0.00 sec) -------------------------------------------------------------------------------- Shared lock on primary key index, other transactions can also obtain shared lock mysql> select * from test where id=1 lock in share mode; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 1 | +----+------+-------+-------+ 1 row in set (0.01 sec) -------------------------------------------------------------------------------- Transaction B can also continue to add shared locksmysql> select * from test where id=1 lock in share mode; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 1 | +----+------+-------+-------+ 1 row in set (0.01 sec) But it cannot be updated because transaction A also adds a shared lockmysql> update test set level=11 where id=1; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction MORE: Unable to add exclusive lock select *from test where id=1 for update; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction You can update unlocked ones, for example, mysql> update test set level=11 where id=2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -------------------------------------------------------------------------------- Transaction A cannot be updated either because transaction B adds a shared lockmysql> update test set level=11 where id=1; ERROR 1205 (HY000): Lock wait timeout exceeded ded; try restarting transaction -------------------------------------------------------------------------------- If any one releases the shared lock, the transaction that exclusively holds the shared lock can update mysql> commit; Query OK, 0 rows affected (0.00 sec) -------------------------------------------------------------------------------- Transaction B releases the lock, and transaction A has exclusive ownership and can update.mysql> update test set level=11 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 1.2 Retrieve data through index, set exclusive lock and row lock 1.2 Retrieve data through index, set exclusive lock and row lock SessionA SessionB mysql> set autocommit=0; mysql> set autocommit=0; Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql> select * from test; mysql> select * from test; -------------------------------------------------------------------------------- +----+-------+-------+-------+ +----+-------+-------+-------+ | id | name | money | level | | id | name | money | level | +----+-------+-------+-------+ +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 | +----+-------+-------+-------+ +----+-------+-------+-------+ 3 rows in set (0.00 sec) 3 rows in set (0.00 sec) -------------------------------------------------------------------------------- Exclusive lock on the primary key index, other transactions can also obtain shared locks mysql> select * from test where id=1 for update; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 1 | +----+------+-------+-------+ 1 row in set (0.01 sec) -------------------------------------------------------------------------------- Transaction B cannot continue to acquire exclusive locks and will wait for mysql> select *from test where id=1 for update; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction MORE: It cannot be updated either, because the update also sets an exclusive lock mysql> update test set level=2 where id=1; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> select * from test where level=1 lock in share mode; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction -------------------------------------------------------------------------------- Transaction A can updatemysql> update test set level=11 where id=1; Query OK, 1 row affected (0.08 sec) Rows matched: 1 Changed: 1 Warnings: 0 -------------------------------------------------------------------------------- Release the exclusive lock mysql> commit; Query OK, 0 rows affected (0.00 sec) -------------------------------------------------------------------------------- Transaction A releases the lock, and transaction B can add an exclusive lockmysql> select * from test where id=1 for update; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 1 | +----+------+-------+-------+ 1 row in set (0.00 sec) 1.3 Update data through index, also set exclusive lock and row lock For update, insert, and delete statements, an exclusive lock is automatically added 1.3 Update data through index, also set exclusive lock, row lock SessionA SessionB mysql> set autocommit=0; mysql> set autocommit=0; Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql> select * from test; mysql> select * from test; -------------------------------------------------------------------------------- +----+-------+-------+-------+ +----+-------+-------+-------+ | id | name | money | level | | id | name | money | level | +----+-------+-------+-------+ +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 | +----+-------+-------+-------+ +----+-------+-------+-------+ 3 rows in set (0.00 sec) 3 rows in set (0.00 sec) -------------------------------------------------------------------------------- When updating the row with id=1, an exclusive lock is set on the row, and other transactions cannot update the row.mysql> update test set level=11 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -------------------------------------------------------------------------------- Transaction B cannot update the row with id=1 and will wait for mysql> update test set level=21 where id=1; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction MORE: You cannot set an exclusive lock mysql> select *from test where id=1 for update; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> select * from test where level=1 lock in share mode; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction -------------------------------------------------------------------------------- Release the exclusive lock mysql> commit; Query OK, 0 rows affected (0.00 sec) -------------------------------------------------------------------------------- Transaction A releases the lock, and transaction B can add an exclusive lockmysql> select * from test where id=1 for update; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 11| +----+------+-------+-------+ 1 row in set (0.00 sec) 2.1 Dirty Read //Dirty read //2.1 Dirty read SessionA SessionB mysql> set autocommit=0; mysql> set autocommit=0; Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) set session transaction isolation set session transaction isolation level read uncommitted; level read uncommitted; Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> select * from test; mysql> select * from test; -------------------------------------------------------------------------------- +----+-------+-------+-------+ +----+-------+-------+-------+ | id | name | money | level | | id | name | money | level | +----+-------+-------+-------+ +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 | +----+-------+-------+-------+ +----+-------+-------+-------+ 3 rows in set (0.00 sec) 3 rows in set (0.00 sec) -------------------------------------------------------------------------------- mysql> update test set level=100 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -------------------------------------------------------------------------------- //Dirty readmysql> select *from test where id=1; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 100 | +----+------+-------+-------+ 1 row in set (0.00 sec) -------------------------------------------------------------------------------- rollback; Query OK, 0 rows affected (0.01 sec) mysql> select *from test where id=1; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 1 | +----+------+-------+-------+ 1 row in set (0.00 sec) 2.2 Non-repeatable read 2.2 Non-repeatable read // Dirty read SessionA SessionB mysql> set autocommit=0; mysql> set autocommit=0; Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) set session transaction isolation set session transaction isolation level read uncommitted; level read uncommitted; Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> select * from test; mysql> select * from test; -------------------------------------------------------------------------------- +----+-------+-------+-------+ +----+-------+-------+-------+ | id | name | money | level | | id | name | money | level | +----+-------+-------+-------+ +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 | +----+-------+-------+-------+ +----+-------+-------+-------+ 3 rows in set (0.00 sec) 3 rows in set (0.00 sec) -------------------------------------------------------------------------------- mysql> update test set level=100 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -------------------------------------------------------------------------------- mysql> select *from test where id=1; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 100 | +----+------+-------+-------+ 1 row in set (0.00 sec) -------------------------------------------------------------------------------- mysql> update test set level=1000 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -------------------------------------------------------------------------------- //Non-repeatable reading//Read three times, the first time is level 1, the second time is 100, and the third time is 1000 mysql> select *from test where id=1; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 1000| +----+------+-------+-------+ 1 row in set (0.00 sec) 2.3 Phantom Read //2.3 Phantom reading SessionA SessionB mysql> set autocommit=0; mysql> set autocommit=0; Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) set session transaction isolation set session transaction isolation level read uncommitted; level read uncommitted; Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> select * from test; mysql> select * from test; -------------------------------------------------------------------------------- +----+-------+-------+-------+ +----+-------+-------+-------+ | id | name | money | level | | id | name | money | level | +----+-------+-------+-------+ +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 | +----+-------+-------+-------+ +----+-------+-------+-------+ 3 rows in set (0.00 sec) 3 rows in set (0.00 sec) -------------------------------------------------------------------------------- mysql> update test set level=100 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -------------------------------------------------------------------------------- mysql> select *from test where id=1; +----+------+-------+-------+ | id | name | money | level | +----+------+-------+-------+ | 1 | tom | 100 | 100 | +----+------+-------+-------+ 1 row in set (0.00 sec) -------------------------------------------------------------------------------- mysql> insert into test (name, money, level) VALUES ('tim', 250, 4); Query OK, 1 row affected (0.01 sec) -------------------------------------------------------------------------------- //Phantom read//Read twice, the second time has more data of Tim//If it is rr level, you need to use current read select * from test lock in share mode; otherwise, because of MVCC, you can't read Tim's datamysql> select * from test; +----+-------+-------+-------+ | id | name | money | level | +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 4 | tim | 250 | 4 | +----+-------+-------+-------+ 4 rows in set (0.00 sec) 3 Gap lock (Net-Key lock)MVCC enables transactions to read currently at the RR level to avoid phantom read problems in the read case, but what about when writing updates? What should I do if I want to insert new data into the range while updating the range? So there is a gap lock. When updating the data in a certain interval, all records in this interval will be locked. For example, update XXX where id between 1 and 100 will lock all records with ids between 1 and 100. It is worth noting that if a record does not exist in this interval, the record will also be locked. At this time, if another transaction adds data to this interval, it must wait for the previous transaction to release the lock resources. There are two purposes for using gap locks: one is to prevent phantom reading; the other is to meet the needs of recovery and assignment. 3.1 Range gap lock, explicit left open and right closed interval //Gap lock (Net-Key lock) Range gap lock, left open right closed interval SessionA SessionB mysql> set autocommit=0; mysql> set autocommit=0; Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql> select * from test; mysql> select * from test; -------------------------------------------------------------------------------- +----+-------+-------+-------+ +----+-------+-------+-------+ | id | name | money | level | | id | name | money | level | +----+-------+-------+-------+ +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 | +----+-------+-------+-------+ +----+-------+-------+-------+ 3 rows in set (0.00 sec) 3 rows in set (0.00 sec) -------------------------------------------------------------------------------- mysql> update test set level=0 where money between 0 and 200; Query OK, 2 rows affected (0.02 sec) Rows matched: 2 Changed: 2 Warnings: 0 Theoretically, the range should be locked to [0,300)-------------------------------------------------------------------------------- insert money=0waitmysql> insert into test (name, money,level) VALUES ('tim',0,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction insert money=90waitmysql> insert into test (name, money,level) VALUES ('tim',90,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction INSERT money=100 WAIT mysql> insert into test (name, money,level) VALUES ('tim',100,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction INSERT money=299 WAIT mysql> insert into test (name, money,level) VALUES ('tim',299,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction Insert money=300 ok mysql> insert into test (name, money, level) VALUES ('tim',300,0); Query OK, 1 row affected (0.00 sec) 3.2 Single Gap Lock Implicit Interval The previous section specifies updating a certain range, but what if only one value is updated? Will there still be gap locks? //Gap lock (Net-Key lock) Single gap lock, left open right closed interval SessionA SessionB mysql> set autocommit=0; mysql> set autocommit=0; Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql> select * from test; mysql> select * from test; -------------------------------------------------------------------------------- +----+-------+-------+-------+ +----+-------+-------+-------+ | id | name | money | level | | id | name | money | level | +----+-------+-------+-------+ +----+-------+-------+-------+ | 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 | | 2 | jack | 200 | 2 | | 2 | jack | 200 | 2 | | 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 | +----+-------+-------+-------+ +----+-------+-------+-------+ 3 rows in set (0.00 sec) 3 rows in set (0.00 sec) -------------------------------------------------------------------------------- mysql> update test set level=0 where money = 200; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 Theoretically, the range should be locked to [0,300)-------------------------------------------------------------------------------- Insert money=0 ok mysql> insert into test (name, money, level) VALUES ('tim',0,0); Query OK, 1 row affected (0.00 sec) Insert money=90 ok mysql> insert into test (name, money, level) VALUES ('tim',90,0); Query OK, 1 row affected (0.00 sec) INSERT money=100 WAIT mysql> insert into test (name, money,level) VALUES ('tim',100,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction INSERT money=150 WAIT mysql> insert into test (name, money,level) VALUES ('tim',150,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction INSERT money=200 WAITmysql> insert into test (name, money,level) VALUES ('tim',200,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction INSERT money=240 WAIT mysql> insert into test (name, money,level) VALUES ('tim',240,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction Insert money=300 ok mysql> insert into test (name, money, level) VALUES ('tim',300,0); Query OK, 1 row affected (0.00 sec) When the interval is not specified, the implicit interval is the interval determined by the values of the two nodes before and after the index B+number, which is also left open and right closed. For the above example, it is the interval [0,300). SummarizeThis is the end of this article about MySQL InnoDB locking mechanism. For more information about MySQL InnoDB locking mechanism, please search previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future! You may also be interested in:
|
<<: 404 error occurs when accessing the homepage of tomcat started in Docker mode
>>: Summary of front-end knowledge in the Gokudō game
Preface Under Linux, compilation and linking requ...
1. Remove backslashes through the "stripslas...
Table of contents 1. Follow the wizard to create ...
MySQL is a relational database management system....
Generally, during the development process, the su...
frame: Style=”border-style:solid;border-width:5px;...
Table of contents 1. Basic Examples 2. Computed p...
Vue components are connected, so it is inevitable...
Web page encoding is translated into English as we...
Table of contents Typical waterfall website Water...
Pop-up news is common in domestic Internet servic...
Preface I have been busy developing a cold chain ...
Table of contents Initially using the callback fu...
First of all, we need to understand that GB2312, ...
If the developer uses Dockerfile to build the ima...