Classic and common deadlock causes and solutions when Mysql is concurrent

1. What locks does Mysql have?

MySQL has three lock levels: page level, table level, and row level.

Table-level lock: low overhead and fast locking; no deadlock; large locking granularity, the highest probability of lock conflict, and the lowest concurrency.

Row-level locks: high overhead, slow locking; deadlocks; the smallest locking granularity, the lowest probability of lock conflicts, and the highest concurrency.

Page locks: overhead and locking time are between table locks and row locks; deadlocks may occur; locking granularity is between table locks and row locks, and the degree of concurrency is average

algorithm:

next KeyLocks lock, lock the record (data) at the same time, and lock the Gap in front of the record

Gap lock, do not lock the record, only record the previous gap

Recordlock lock (lock data, not lock Gap)

So actually Next-KeyLocks = Gap lock + Recordlock lock

2. Under what circumstances will it cause deadlock

The so-called deadlock <deadlock>: refers to a phenomenon in which two or more processes are waiting for each other due to competition for resources during the execution process. If there is no external force, they will not be able to advance. At this time, it is called When the system is in a deadlock state or the system has a deadlock, these processes that are always waiting for each other are called deadlock processes.

Table-level locks will not cause deadlocks. Therefore, the solution to deadlocks is mainly for the most commonly used InnoDB.

The key to deadlock is that the order of locking of two (or more) sessions is inconsistent.

Then the corresponding key to solving the deadlock problem is: let different sessions lock in order

3. Some common deadlock cases

Case number one:

Demand: split the invested money into several random allocations to borrowers.

The initial business process idea is as follows:

After the investor invests, the amount is randomly divided into several parts, and then a few are randomly selected from the borrower table, and then the balance in the borrower table is updated by selecting for update one by one.

The abstraction is that a session will have several statements as follows through the for loop:

select * from xxx where id='随机id' for update

Basically, the program will deadlock shortly after it is started.

This is arguably the most classic deadlock situation.

For example, when two users invest at the same time, the amount of user A is randomly divided into 2 shares, which are distributed to borrowers 1 and 2.

The amount of user B is randomly divided into 2 parts and distributed to the borrower 2, 1

Since the order of locking is not the same, deadlocks of course appear very quickly.

> The improvement to this problem is very simple, just lock all the allocated borrowers directly at one time.

select * from xxx where id in (xx,xx,xx) for update

> The list value mysql in in will be automatically sorted from small to large, and the locking is also a lock that is added from small to large.

For example (the following session id is the primary key):

Session1:

mysql&gt; select * from t3 where id in (8,9) for update;

+----+--------+------+---------------------+

| id | course | name | ctime               |

+----+--------+------+---------------------+

|  8 | WA     | f    | 2016-03-02 11:36:30 |

|  9 | JX     | f    | 2016-03-01 11:36:30 |

+----+--------+------+---------------------+
rows in set (0.04 sec)

Session2:

select * from t3 where id in (10,8,5) for update;

lock waiting...

In fact, the record with id=10 is not locked at this time, but the record with id=5 has been locked, and the lock is waiting here with id=8.

If you don't believe me, please see

Session3:

mysql&gt; select * from t3 where id=5 for update;

lock waiting

Session4:

mysql&gt; select * from t3 where id=10 for update;

+----+--------+------+---------------------+

| id | course | name | ctime               |

+----+--------+------+---------------------+

| 10 | JB     | g    | 2016-03-10 11:45:05 |

+----+--------+------+---------------------+
row in set (0.00 sec)

In other sessions, id=5 cannot be locked, but id=10 can be locked.

Case 2:

In development, such judgment requirements are often made: query according to field value (with index), if it does not exist, insert; otherwise, update.

Taking id as the primary key as an example, there is currently no row with id=22

Session1:

select * from t3 where id=22 for update;

Empty set (0.00 sec)

session2:

select * from t3 where id=23  for update;

Empty set (0.00 sec)

Session1:

insert into t3 values(22,'ac','a',now());

lock waiting...

Session2:

insert into t3 values(23,'bc','b',now());

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

> When the existing row is locked (primary key), mysql only has row lock. > When locking a row that does not exist (even if the condition is the primary key), mysql will lock a range (with gap lock)

The locked range is: (infinitely small or less than the maximum value of the locked id in the table, infinite or greater than the minimum value of the locked id in the table)

For example: if there is an existing id in the table (11, 12)

then lock(12, infinity)

If the existing id in the table is (11, 30)

then lock (11, 30)

> The solution to this deadlock is:

insert into t3(xx,xx) on duplicate key update `xx`='XX';

> Use mysql-specific syntax to solve this problem. Because the insert statement is for the primary key, the inserted row will only have a row lock regardless of whether it exists or not.

Case 3:

Go directly to the scene:

mysql&gt; select * from t3 where id=9 for update;

+----+--------+------+---------------------+

| id | course | name | ctime               |

+----+--------+------+---------------------+

|  9 | JX     | f    | 2016-03-01 11:36:30 |

+----+--------+------+---------------------+
row in set (0.00 sec)

Session2:

mysql&gt; select * from t3 where id&lt;20 for update;

lock waiting

Session1:

mysql&gt; insert into t3 values(7,'ae','a',now());

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

This is similar to the other cases in case 1, except that session 1 does not play cards according to common sense.

Session2 is waiting for the lock with id=9 of Session1, and session2 holds locks from 1 to 8 (note that the range from 9 to 19 is not locked by session2), and finally, session1 has to wait for session2 when inserting a new row, so it died lock happened.

This kind of generally does not appear in business requirements, because you lock the id=9, but you want to insert the row with id=7, which is a bit jumpy, of course, there must be a solution, that is, re-processing the business requirements, avoid such writing.

As a side note, I recommend two good articles

Case 4:

http://hedengcheng.com/?p=844

MySQL lock processing analysis:

http://hedengcheng.com/?p=771

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324156668&siteId=291194637