[MySQL] Transaction and Lock (5): Analysis of Deadlock Problem

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 you wait in a loop, it may cause a 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 how the third deadlock occurs and how to avoid it.

1. Lock release and blocking

When is the lock released? The transaction ends (commit, rollback) or 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, and even drag across the database.

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction。

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. The occurrence and detection of deadlock

To put it simply, the deadlock is that thread 1 takes the A lock and other B locks, while thread 2 takes the B lock and other A locks. The deadlock is demonstrated as follows:

Transaction1 Transaction2
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 FORM t2 WHERE id=1;

In the first transaction, a deadlock is detected and immediately exited. The second transaction obtained the lock without waiting for 50 seconds:

Insert picture description here

Insert picture description here

Note: The Delete id=1 of Transaction2 will soon enter the deadlock, because Transaction1 has been holding the lock of id=1

1) 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 automatically detect it through an algorithm (wait-for graph).

2) So what conditions need to be met for deadlock?

The conditions of the deadlock: because the lock itself is mutually exclusive, so

  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

Example: There are two directors in a barber shop. A Director Tony is responsible for haircutting, and a Director Kelvin is responsible for washing hair.

  1. Tony can't cut the heads of two people at the same time, this is called mutual exclusion.
  2. When Tony is cutting someone's head, you can't let him stop and help you cut your head. This means that you can't be forcibly deprived.
  3. If Tony’s client says to Director Kelvin: How can I cut my hair if you don’t wash my hair? Kelvin’s client said to Director Tony: How do I wash my hair if you don’t cut my hair? This is called a waiting loop.

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 the lock log information

The SHOW STATUS command includes some row lock information:

show status like 'innodb_row_lock_%';

Insert picture description here

  • Innodb_row_lock_current_waits: the number of locks currently waiting for;
  • Innodb_row_lock_time: The total length of time from the system startup to the current lock, in ms;
  • Innodb_row_lock_time_avg: the average time spent in each wait;
  • Innodb_row_lock_time_max: the time it takes to wait for the longest time since the system was started; Innodb_row_lock_waits: the total number of waits since the system was started.

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

select * from information_schema.INNODB_TRX; -- 当前运行的所有事务 ,还有具体的语句
select * from information_schema.INNODB_LOCKS; -- 当前出现的锁
select * from information_schema.INNODB_LOCK_WAITS; -- 锁等待的对应关系

Insert picture description here

What happens after finding out the transaction holding 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 kill 1314 and kill 1316.

Of course, the deadlock problem cannot be solved by killing the thread every time. This is a symptom, not a root cause. 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 of 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 things into small ones
  6. Use equivalent query instead of range query to query data, hit the record, avoid the impact of gap lock on concurrency

Guess you like

Origin blog.csdn.net/weixin_43935927/article/details/114001473