Mysql transaction and lock knowledge (3) deadlock

Preface

When we use locks, there is a problem that needs to be noted and avoided. We know that exclusive locks have the characteristics of mutual exclusion. When a transaction or a thread holds a lock, it will prevent other threads from acquiring the lock. At this time, it will cause blocking waiting. If it is cyclically waiting, it may cause deadlock.
We need to analyze this problem from several aspects. One is why the lock is not released, the second is what to do if it is blocked, and the third is how deadlock occurs and how to avoid it.

Deadlock

1. Lock release and blocking

When is the lock released?
The transaction ends (commit, rollback); the client connection is disconnected.
If a transaction has not released the lock, how long will other transactions be blocked? Will you wait forever? If so, in the case of relatively high concurrent access, if a large number of transactions are suspended due to the inability to obtain the required locks immediately, it will take up a lot of computer resources, cause serious performance problems, or even drag the database across.

MySQL has a parameter to control the waiting time for acquiring a lock, the default is 50 seconds.

show VARIABLES like 'innodb_lock_wait_timeout';

Insert picture description here
In the case of a deadlock, the lock cannot be acquired no matter how long it takes. In this case, do I need to wait for 50 seconds? Isn't that a waste of 50 seconds?

Let's first look at when the deadlock will occur.

2. Occurrence and detection of deadlock

Deadlock demo
Case 1:

Session 1 Session 2
begin;
select * from t2 where id =1 for update;
begin;
delete from t2 where id =4 ;
update t2 set name= ‘4d’ where id =4 ;
delete from t2 where id =1;

Case 2:

Session 1 Session 2
begin;
select * from t1 where id =1 lock in share mode;
begin;
select * from t1 where id =1 lock in share mode;
update t1 set name= ‘1a’ where id =1;
update t1 set name= ‘1a’ where id =1;

We see: In the first transaction, a deadlock is detected, and it is immediately retired. The second transaction is locked, and there is no need to wait for 50 seconds;

[Err] 1213 ・ Deadlock found when trying to get lock; try restarting transaction

Why can it be detected directly? It is because the occurrence of deadlock needs to meet certain conditions, so when a deadlock occurs, InnoDB can generally be automatically detected through an algorithm (wait-for graph).

The conditions of the deadlock (because the lock itself is mutually exclusive):

  1. Only one transaction can hold this lock at the same time;
  2. Other transactions need to acquire the lock after the transaction releases the lock, and cannot be forcibly deprived;
  3. When multiple transactions form a waiting loop, a deadlock occurs.

This is also the reason why table locks do not deadlock, because the resources of table locks are acquired at one time.

Session 1 Session 2
begin;
lock tables t2 write;
begin;
lock tables t1 write;
lock tables t1 write; // BLOCKED
//0K, the above statement is no longer blocked, the table lock of t2 is released, and the table lock of t1 is acquired lock tables t2 write;
// OK, get the table lock of t2

If the lock has not been released, it may cause a lot of blocking or deadlock, resulting in a decrease in system throughput. At this time, it is necessary to check which transactions are holding the lock.

3. View lock information (log)

First of all, the SHOW STATUS command includes some row lock information:

show status like 'innodb_row_lock_%';

Insert picture description here

  • lnnodb_row_lock_current_waits: the number of locks currently waiting for;
  • lnnodb_row_lock_time: The total length of time from the system startup to the current lock, in ms;
  • lnnodb_row_lock_time_avg: the average time spent in each waiting;
  • lnnodb_row_lock_time_max: The time it takes to wait for the longest time since the system is started;
  • lnnodb_row_lock_waits: The total number of waits from the start of the system to the present.

The SHOW command is a summary information. InnoDB also provides three tables to analyze transactions and locks:

select * from information_schema.INNODB_TRX;--当前运行的所有事务,还有具体的语句

Insert picture description here

select * from information_schema.INNODB_LOCKS; -- 当前出现的锁

Insert picture description here

select * from information_schema.INNODB_LOCK_WAITS; -- 锁等待对应的关系

Insert picture description here
More detailed lock information, open standard monitoring and lock monitoring:

set GLOBAL innodb_status_output=ON;
set GLOBAL innodb_status_output_locks=ON;

After analyzing the lock log to find out the transaction that holds the lock?
If a transaction holds the lock for a long time and does not release it, you can kill the thread ID corresponding to the transaction, which is trx_mysql_thread_id in the INNODB_TRX table, for example, execute kill4, kill7, and kill8.
Of course, the problem of deadlock cannot be solved by the kil thread every time. This is a symptom, not a permanent cure. We should try our best to avoid it on the application side, that is, during the encoding process.

What are some ways to avoid deadlock?

4. Avoidance of deadlock

  1. In the program, when operating multiple tables, try to access them in the same order (to avoid waiting loops);
  2. When operating a single table data in batches, sort the data first (to avoid waiting loops);
  3. Apply for a sufficient level of lock, if you want to manipulate data, apply for an exclusive lock;
  4. Try to use indexes to access data, avoid operations without where conditions, and avoid locking tables;
  5. If possible, turn big affairs into small ones;
  6. Use equivalent query instead of range query to query data, hit records, and avoid the impact of gap locks on concurrency.

Guess you like

Origin blog.csdn.net/nonage_bread/article/details/113114509