An article to understand MySQL row locks, table locks, and gap locks in detail

Ready to work

Create table tb_innodb_lock

drop table if exists test_innodb_lock;
CREATE TABLE test_innodb_lock (
    a INT (11),
    b VARCHAR (20)
) ENGINE INNODB DEFAULT charset = utf8;
insert into test_innodb_lock values (1,'a');
insert into test_innodb_lock values (2,'b');
insert into test_innodb_lock values (3,'c');
insert into test_innodb_lock values (4,'d');
insert into test_innodb_lock values (5,'e');

Create index

create index idx_lock_a on test_innodb_lock(a);
create index idx_lock_b on test_innodb_lock(b);

MySQL lock demo

  • First change the automatic commit transaction to manual commit:set autocommit=0;

  • We start two session windows A and B, simulating one grabbing the lock and the other being blocked without grabbing.

Row lock (write & read)

  • A window execution

update test_innodb_lock set b='a1' where a=1;
SELECT * from test_innodb_lock;

1.png

We can see the updated result in window A

  • B window execution

SELECT * from test_innodb_lock;

2.png

We can see that the B window cannot see the updated results, but the old data is still seen. This is because the record of a = 1 was locked by the SQL statement executed by the A window, and the commit operation was not executed. So window B still sees the old data. This is the "read committed" in the MySQL isolation level.

  • Window A executes commit operation

COMMIT;


  • Window B query

SELECT * from test_innodb_lock;

3.png

At this time we found that window B has read the latest data

Row lock (write & write)

  • Window A performs the update of a = 1 record

update test_innodb_lock set b='a2' where a=1;

At this time, there is no commit, and the lock is held by window A.

  • Window B also updates the record of a = 1

update test_innodb_lock set b='a3' where a=1;

4.png

As you can see, window B has been blocked because window A has not yet executed commit and still holds the lock. Window B can't grab the lock recorded in the row a = 1, so it has been blocked waiting.

  • Window A executes commit operation

COMMIT;

  • Changes in window B

5.png

You can see that window B has been executed successfully at this time

Table lock

When an index fails, the row lock will be upgraded to a table lock. One of the methods for index failure is to automatically or manually change the index. The a field itself is an integer, we add quotation marks, it becomes a String, this time the index will be invalid.

  • Window A updates the record of a = 1

update test_innodb_lock set b='a4' where a=1 or a=2;

  • Window B updates the record of a = 2

update test_innodb_lock set b='b1' where a=3;

6.png

At this time, it was discovered that although the updated rows of window A and B were different, window B was still blocked. Because the index of window A failed, the row lock was upgraded to table lock, and the entire table was locked. Index window B is blocked.

  • Window A executes commit operation

COMMIT;

  • Changes in window B

7.png

You can see that window B has been executed successfully at this time

Gap lock

  • What is a gap lock

When we use range conditions to query data, InnoDB will lock the data in this range. For example, there are 4 pieces of data with id: 1, 3, 5, and 7, we look for data in the range of 1-7. Then 1-7 will be locked. 2, 4, and 6 are also in the range of 1-7, but these data records do not exist, these 2, 4, and 6 are called gaps.

  • The harm of gap lock

When searching the range, all data in the entire range will be locked. Even some data that does not exist in this range will be locked innocently. For example, I want to insert 2 in 1, 3, 5, and 7, this time 1 -7 is locked, and 2 cannot be inserted at all. In some scenarios, it will have a big impact on performance

  • Gap lock demo

We first modify the value of field a to 1, 3, 5, 7, 9

  • Window A updates the data in the range a = 1~7

update test_innodb_lock set b='b5' where a>1 and a<7;

  • Window B inserts data at a = 2

insert into test_innodb_lock values(2, "b6");

8.png

At this time, it is found that the operation of updating a = 2 in window B has been waiting, because the data in the range of 1~7 is locked by the gap and locked. Only when window A executes commit, window B's a = 2 can the update succeed

Row lock analysis

  • Execute SQL analysis commands

show status like 'innodb_row_lock%';

9.png

  • Variable_name description

    • Innodb_row_lock_current_waits: The number of locks currently waiting for.

    • Innodb_row_lock_time: The length of time from the system startup to the current lock.

    • Innodb_row_lock_time_avg: The average time spent waiting for the lock each time.

    • Innodb_row_lock_time_max: The longest time it takes for the lock to wait since the system is started.

    • Innodb_row_lock_waits: The total number of waits for locks after the system was started up to now.

At last

Thank you all for seeing here, the article has deficiencies, and you are welcome to point out; if you think it is well written, please give me a thumbs up.


Guess you like

Origin blog.51cto.com/14849432/2542676