InnoDB鎖衝突案例演示

aaron8219發表於2018-08-14
 
Preface
 
    As we know,InnoDB is index organized table.InnoDB engine supports row-level lock base on indexes,if there`re no indexes on a certain table the record locks will upgrade to “table-level”(not really table lock,just locks all the records in the table) locks.Furthe more,in RR transaction isolation mode,It`s more complicated.`cause there`re gap locks(together with record locks,we call them next key locks) to prevent phantom read between multiple tansactions.Let`s do some test watch the locking conflicts.
 
Procedure
 
Crete a test table as below.
 1 zlm@192.168.56.100:3306 [zlm]>create table t1(
 2     -> c1 int unsigned not null default `0`,
 3     -> c2 int unsigned not null default `0`,
 4     -> c3 int unsigned not null default `0`,
 5     -> c4 int unsigned not null default `0`,
 6     -> primary key(c1),
 7     -> key(c2)
 8     -> ) engine=innodb;
 9 Query OK, 0 rows affected (0.02 sec)
10 
11 zlm@192.168.56.100:3306 [zlm]>insert into t1(c1,c2,c3,c4) values(0,0,0,0),(1,1,1,0),(3,3,3,0),(4,2,2,0),(6,2,5,0),(8,6,6,0),(10,4,4,0);
12 Query OK, 7 rows affected (0.01 sec)
13 Records: 7  Duplicates: 0  Warnings: 0
14 
15 zlm@192.168.56.100:3306 [zlm]>select * from t1;
16 +----+----+----+----+
17 | c1 | c2 | c3 | c4 |
18 +----+----+----+----+
19 |  0 |  0 |  0 |  0 |
20 |  1 |  1 |  1 |  0 |
21 |  3 |  3 |  3 |  0 |
22 |  4 |  2 |  2 |  0 |
23 |  6 |  2 |  5 |  0 |
24 |  8 |  6 |  6 |  0 |
25 | 10 |  4 |  4 |  0 |
26 +----+----+----+----+
27 7 rows in set (0.01 sec)
28 
29 zlm@192.168.56.100:3306 [(none)]>select @@transaction_isolation;
30 +-------------------------+
31 | @@transaction_isolation |
32 +-------------------------+
33 | REPEATABLE-READ         | //Make surej in RR transaction isolation level.
34 +-------------------------+
35 1 row in set (0.00 sec)
36 
37 zlm@192.168.56.100:3306 [(none)]>show variables like `innodb_status_output_locks`;
38 +----------------------------+-------+
39 | Variable_name              | Value |
40 +----------------------------+-------+
41 | innodb_status_output_locks | ON    |
42 +----------------------------+-------+
43 1 row in set (0.00 sec)

 

Test 1. session1 executes “select …  for update” and session2 executes “select … lock in share mode”.(conflict)
 1 //Session1:
 2 zlm@192.168.56.100:3306 [zlm]>begin;select * from t1 where c1=3 for update;
 3 Query OK, 0 rows affected (0.00 sec)
 4 
 5 +----+----+----+----+
 6 | c1 | c2 | c3 | c4 |
 7 +----+----+----+----+
 8 |  3 |  3 |  3 |  0 |
 9 +----+----+----+----+
10 1 row in set (0.00 sec)
11 
12 //Session2:
13 monitor@192.168.56.100:3306 [zlm]>begin;select * from t1 where c1=3 lock in share mode;
14 Query OK, 0 rows affected (0.00 sec)
15 
16 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
17 
18 //Session2 requested a "S" record lock on the primary key column where c1=3 while session1 has holded the "X" record lock on the same position,so session2 was blocked util lock timeout.

 

Test 2. session1 executes “select …  for update” and session2 executes ordinary query.(compatible)
 1 //Session1:
 2 zlm@192.168.56.100:3306 [zlm]>begin;select * from t1 where c1=3 for update;
 3 Query OK, 0 rows affected (0.00 sec)
 4 
 5 +----+----+----+----+
 6 | c1 | c2 | c3 | c4 |
 7 +----+----+----+----+
 8 |  3 |  3 |  3 |  0 |
 9 +----+----+----+----+
10 1 row in set (0.00 sec)
11 
12 //Session2:
13 monitor@192.168.56.100:3306 [zlm]>select * from t1 where c1=3;
14 +----+----+----+----+
15 | c1 | c2 | c3 | c4 |
16 +----+----+----+----+
17 |  3 |  3 |  3 |  0 |
18 +----+----+----+----+
19 1 row in set (0.00 sec)
20 
21 //Session1 didn`t change this time and session2 request for non-lock consistent read.It read records from a consistent snapshop without locking.

 

Test 3. session1 executes “select …  lock in share mode” and session2 executes “select … for update”.(conflict)
 1 //Session1:
 2 zlm@192.168.56.100:3306 [zlm]>begin;select * from t1 where c3=7 lock in share mode;
 3 Query OK, 0 rows affected (0.01 sec)
 4 
 5 Empty set (0.00 sec)
 6 
 7 //Session2:
 8 monitor@192.168.56.100:3306 [zlm]>begin;select * from t1 where c3=10 for update;
 9 Query OK, 0 rows affected (0.00 sec)
10 
11 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
12 
13 //Although there`s no record satisfied with c3=7 but notice that there`s no index on c3 column.Therefore,the session1 has holded a "S" record for all the records on column c1 in table t1.Then session2 asked for the "X" record lock for "c3=10"(even it does not exixt),it was blocked.

 

Test 4. session1 executes “select …  lock in share mode” and session2 executes “select … for update”.(conflict)
 1 //Session1:
 2 zlm@192.168.56.100:3306 [zlm]>begin;select * from t1 where c3=7 lock in share mode;
 3 Query OK, 0 rows affected (0.00 sec)
 4 
 5 Empty set (0.00 sec)
 6 
 7 //Session2:
 8 monitor@192.168.56.100:3306 [zlm]>begin;select * from t1 where c1=6 for update;
 9 Query OK, 0 rows affected (0.00 sec)
10 
11 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
12 
13 //This is similar with "test 3".Session1 has holded a "S" record lock of all records on column c3.The record where c1=6 means c3=5,it`s also in the range of all records.So session2 was blocked.

 

Test 5. session1 executes “select …  for update” and session2 executes “select … for update”.(conflict)
 
 1 //Session1:
 2 zlm@192.168.56.100:3306 [zlm]>begin;select * from t1 where c2=2 and c3=5 for update;
 3 Query OK, 0 rows affected (0.00 sec)
 4 
 5 +----+----+----+----+
 6 | c1 | c2 | c3 | c4 |
 7 +----+----+----+----+
 8 |  6 |  2 |  5 |  0 |
 9 +----+----+----+----+
10 1 row in set (0.00 sec)
11 
12 //Session2:
13 monitor@192.168.56.100:3306 [zlm]>begin;select * from t1 where c2=2 and c3=7 for update;
14 Query OK, 0 rows affected (0.00 sec)
15 
16 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
17 
18 //Because of the secondary index key on column c2,it generated a "X" record lock and a gap lock(record + gap = next key lock).Although the gap lock between two sessions can be coexistent,but record locks do not.So session2 was blocked.

 

Test 6. session1 executes “select …  for update” and session2 executes “select … for update”.(compatible)
 1 //Session1:
 2 zlm@192.168.56.100:3306 [zlm]>begin;select * from t1 where c2=2 and c3=5 for update;
 3 Query OK, 0 rows affected (0.00 sec)
 4 
 5 +----+----+----+----+
 6 | c1 | c2 | c3 | c4 |
 7 +----+----+----+----+
 8 |  6 |  2 |  5 |  0 |
 9 +----+----+----+----+
10 1 row in set (0.00 sec)
11 
12 //Session2:
13 monitor@192.168.56.100:3306 [zlm]>begin;select * from t1 where c2=3 and c3=7 for update;
14 Query OK, 0 rows affected (0.00 sec)
15 
16 Empty set (0.00 sec)
17 
18 //This time session2 was not blocked.They`ve requested a different "X" record lock individually even they still hold the gap lock.

 

Test 7. session1 executes “select …  for update” and session2 executes “select … for update”.(conflict)
 1 //Session1:
 2 zlm@192.168.56.100:3306 [zlm]>begin;select * from t1 where c2=2 and c3=2 for update;
 3 Query OK, 0 rows affected (0.00 sec)
 4 
 5 +----+----+----+----+
 6 | c1 | c2 | c3 | c4 |
 7 +----+----+----+----+
 8 |  4 |  2 |  2 |  0 |
 9 +----+----+----+----+
10 1 row in set (0.00 sec)
11 
12 //Session2:
13 monitor@192.168.56.100:3306 [zlm]>begin;select * from t1 where c1=4 and c3=10 for update;
14 Query OK, 0 rows affected (0.00 sec)
15 
16 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
17 
18 //The query condition in session2 is c1=4.It means c2=2,this is similar with test 5(asked for the equal line).

 

Test 8. session1 executes “select …  for update” and session2 executes “select … for update”.(compatible)
 1 //Session1:
 2 zlm@192.168.56.100:3306 [zlm]>begin;update t1 set c4=20 where c2>=4;
 3 Query OK, 0 rows affected (0.00 sec)
 4 
 5 Query OK, 2 rows affected (0.00 sec)
 6 Rows matched: 2  Changed: 2  Warnings: 0
 7 
 8 //Session2:
 9 monitor@192.168.56.100:3306 [zlm]>begin;select * from t1 where c1=7 for update;
10 Query OK, 0 rows affected (0.00 sec)
11 
12 Empty set (0.00 sec)
13 
14 //The records according to the query condition c2>=4 were c1=8 and c1=10.
15 //Even though there`s a index key on c1 but it`s a primary key which doesn`t generate gap lock.So session2 `s asking for "X" record lock of c1=7 was not blocked.

 

Summary
  • We should pay more attention to innodb row-level locks.If there`s no key on the relevant column,the locks will be escalated to “table-level”(all records will be locked) locks.
  • In the RR transaction isolation level,Secondary index generates gap locks(LOCK_ORDINARY) to prevent phantom read while primary index and unique index do not.They only hold record locks(LOCK_REC_NOT_GAP).
  • In the RC transaction isolation level,there`re no gap locks.Therefore,it`s concurrency is better than that in RR mode,but the consistency is poor as well.
  • As for which transaction isolation level we should choose is depend on your purpose:for more consistency or for more concurrency.
 

相關文章