Case Study database deadlock

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/wufaliang003/article/details/91410623

I. Introduction

Deadlock, in fact, is a very interesting and very challenging technical problems, probably each part of the development and DBA students will meet in the course of their work. Stories About Deadlock I will continue to write a series of analysis, hoping to help friends want to know deadlock

Two case studies

2.1 Business scene

User input goods, the application will check in advance whether the same record, if you remove and then insert; if not directly inserted.

2.2 Environmental instructions

MySQL 5.7.22 transaction isolation level RC mode.

  1. create table t(id int not null auto_increment primary key ,

  2. a int not null default 0,

  3. b int not null default 0,

  4. c int not null default 0,

  5. unique key uk_ab(a,b)) engine=innodb;

  6. insert into t(a,b,c) values(1,1,1),(3,3,2),(6,6,3),(9,9,5);

2.3 Background

A knowledge point

INSERT operations when inserting or updating records, check the duplicate key or a duplicate key is marked for deletion (article case), for ordinary INSERT / UPDATE, will add attributes lock LOCK_S next-key lock. For this or similar REPLACE INTO SQL INSERT ... ON DUPLICATE X lock is applied. And for different index types are different:

Code Location row0ins.cc:2013

  1. if (flags & BTR_NO_LOCKING_FLAG) {

  2. /* Set no locks when applying log

  3. in online table rebuild. */

  4. } else if (allow_duplicates) {

  5.  

  6. /* If the SQL-query will update or replace

  7. duplicate key we will take X-lock for

  8. duplicates ( REPLACE, LOAD DATAFILE REPLACE,

  9. INSERT ON DUPLICATE KEY UPDATE). */

  10.  

  11. err = row_ins_set_exclusive_rec_lock(

  12. lock_type, block, rec, index, offsets, thr);

  13. } else {

  14.  

  15. err = row_ins_set_shared_rec_lock(

  16. lock_type, block, rec, index, offsets, thr);

  17. }

Knowledge point two

When a record is inserted into a data page, the function calls will always be lock_rec_insert_check_and_lock lock check (except insertion of indexing data), the lock will check whether there is a next record current object insertion position, where the does not refer to a physically continuous recording, but in accordance with the next record in a logical order. If the lock object does not exist on the next record: If the record is to update the maximum transaction ID on the secondary index page on the secondary index for the ID of the current transaction; direct return success.

If there is a next record lock object, it is necessary to determine whether the lock object is locked GAP. If the GAP is locked, and determine intent and insert GAP lock conflict, it is necessary to wait for the current operation, plus lock type LOCKX | LOCKGAP | LOCKINSERTINTENTION, and enters a wait state. Code Location lock0lock.cc:5965

  1. *inherit = TRUE;

  2. /* If another transaction has an explicit lock request which locks

  3. the gap, waiting or granted, on the successor, the insert has to wait.

  4.  

  5. An exception is the case where the lock by the another transaction

  6. is a gap type lock which it placed to wait for its turn to insert. We

  7. do not consider that kind of a lock conflicting with our insert. This

  8. eliminates an unnecessary deadlock which resulted when 2 transactions

  9. had to wait for their insert. Both had waiting gap type lock requests

  10. on the successor, which produced an unnecessary deadlock. */

  11.  

  12. const ulint type_mode = LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION;

  13. const lock_t* wait_for = lock_rec_other_has_conflicting(

  14. type_mode, block, heap_no, trx);

  15. if (wait_for != NULL) {

  16. RecLock rec_lock(thr, index, block, heap_no, type_mode);

  17. trx_mutex_enter(trx);

  18. err = rec_lock.add_to_waitq(wait_for);

  19. trx_mutex_exit(trx);

  20. } else {

  21. err = DB_SUCCESS;

  22. }

I verified by the following test. Table 2.2 data structure and the test data structure.

A test case

  1. sess1

  2. mysql > delete from t where a=3 and b=3 ;

  3. Query OK, 1 row affected (0.00 sec)

  4. sess2

  5. mysql >update t set c=6 where a=6 and b=6 and c=3;

  6. sess1

  7. mysql >insert into t(a,b,c) values(3,3,5); --产生锁等待

insert (3,3,5) application lock S is blocked sess2 delete hold the Lock X row lock,

show engine innodb status does not show the complete lock S is what locks. We continue to test.

Test Case II

  1. T1 sess1

  2. mysql > delete from t where a=3 and b=3 ;

  3. mysql > insert into t(a,b,c) values(3,3,5);

  4.  

  5. T2 sess2

  6. mysql > insert into t(a,b,c) values(3,2,6);

  7.  

  8. T3 sess3

  9. mysql > insert into t(a,b,c) values(3,4,5);

Wherein sess2 sess3 waiting application lock_mode X locks gap before rec insert intention waiting, apparently held sess1 LOCK S Next key lock obstruction. And is (1,3), (3,6) of the two sections

Obviously a test case in sess2 hold record (6,6) of the lock X record lock but not gap, will block insert (3,3) application LOCK S Next key lock.

2.4 Test Case

2.5 Deadlock log

  1. 2019-04-27 23:26:16 0x7f26cc77b700

  2. *** (1) TRANSACTION:

  3. TRANSACTION 2489, ACTIVE 43 sec inserting

  4. mysql tables in use 1, locked 1

  5. LOCK WAIT 5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2

  6. MySQL thread id 121125, OS thread handle 139804595451648, query id 526 localhost msandbox update

  7. insert into t(a,b,c) values(3,3,3),(3,1,2)

  8. *** (1) WAITING FOR THIS LOCK TO BE GRANTED:

  9. RECORD LOCKS space id 26 page no 4 n bits 80 index uk_ab of table `test`.`t` trx id 2489 lock mode S waiting

  10. *** (2) TRANSACTION:

  11. TRANSACTION 2490, ACTIVE 36 sec inserting

  12. mysql tables in use 1, locked 1

  13. 6 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 3

  14. MySQL thread id 121123, OS thread handle 139804615882496, query id 528 localhost msandbox update

  15. insert into t(a,b,c) values(6,6,6),(6,5,4)

  16. *** (2) HOLDS THE LOCK(S):

  17. RECORD LOCKS space id 26 page no 4 n bits 80 index uk_ab of table `test`.`t` trx id 2490 lock_mode X locks rec but not gap

  18. *** (2) WAITING FOR THIS LOCK TO BE GRANTED:

  19. RECORD LOCKS space id 26 page no 4 n bits 80 index uk_ab of table `test`.`t` trx id 2490 lock_mode X locks gap before rec insert intention waiting

  20. *** WE ROLL BACK TRANSACTION (1)

2.6 Analysis of deadlock log

T1 delete a = 3 and b = 3 uncommitted, holds the secondary index (3,3) line lock record is marked as stale.

T2 delete a = 6 and b = 6 uncommitted, holds the secondary index (6,6) line lock record is marked as stale.

T3 insert (3,3,3), the check is marked for deletion (3,3), applying plus LOCK_S next-key lock. But in the checking to the next record holders Lock X record lock. So wait.

Interval T4 insert (6,5,4) writing (3,6), the applicant lock_mode Locks GAP before X-REC INSERT Waiting at intention , but is waiting for the session T3 LOCK_S Next-Key Lock . Then waiting for each other, a deadlock occurs.

2.7 Solution

Essentially concurrent operation of adjacent record results in a deadlock. And the development of communication, business logic will make changes, if the number of items found records of entry and exist of the number of records updated to do the same, there is written directly. Reducing the possibility of directly adjacent recording operation.

Three summary

The above analysis is based on their ability to read the code out of halfway decent, it may not be entirely correct. If you have additional comments, please Paizhuan.

No micro-channel public attention and headlines today, excellent article continued update. . . . .

 

 

Guess you like

Origin blog.csdn.net/wufaliang003/article/details/91410623