Analysis of Deadlock Deadlock Scenarios When mysql Insert

Case 1:
There is a table A, update first, if the number of affected rows is 0, execute INSERT to insert data. A very common scenario, and it has been running for a long time in production without any problems. But once in the test environment, there was a deadlock during stress testing. Deadlock found when trying to get lock; try restarting transaction
Insert picture description here

Because you are not familiar with mysql locks, why does insert also deadlock? Isn't it usually deadlock during update? Very curious, so I started to look for the reason...

The mysql lock is related to the isolation level set by the database. Different isolation levels have different locks, as long as they are used to solve problems like dirty reads, phantom reads, and repeatable reads.
select @@tx_isolation; – View the isolation level
Insert picture description here

The isolation level is RR (repeatable read). We know that in this isolation level, in order to solve the problem of phantom reads, there will be gap locks and Next-key locks (row locks + gap locks), that is, in the update and delete statements Later, a gap lock and a Next-key lock will be generated. If in concurrency, two transactions have executed the UPDATE statement (each holding the gap lock) beforehand. When INSERT, first obtain the insert intention lock on the insert gap. Since there is a conflict between the inserted data gaps, they will wait for each other to acquire the insertion intention lock, that is, compete with each other, which will eventually lead to a deadlock.

This also explains why there is a deadlock in the test environment.
solve:

  1. No transaction is used, that is, no transaction execution, but if an exception occurs, data inconsistency will occur.
  2. Adjust the transaction isolation level to read commit, RC level will not generate gap lock

Since we all know the importance of transactions, we choose the second method and change the isolation level to RC. We are generally at this level in the production environment, so it also explains why this problem does not occur in production.

Transaction isolation level adjustment can be achieved through spring's declarative transaction method, through the annotation @Transactional

@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
public void calculationEntry(List<CampaignFeedback> campaignFeedbackList, String groovyScript) {
    
    
    //todo
}

After the pressure test again, the deadlock problem no longer occurs.

Case 2:
Due to business needs, I often update or write to a table, and I don't want to check whether it exists and then insert it every time, so I use mysql replace into to achieve.
The replace into syntax is that if there is a primary key or a unique index in the table, it will judge whether it exists according to this dimension, and if it exists, it will delete in insert first, that is, it will operate in two steps and does not guarantee atomicity.

After starting to use it, I think it is very convenient. After all, there is no need to query by yourself, mysql automatically completes it for us. But when it came to the pressure test, the deadlock appeared again. . . . . .

Because of the previous experience, this is not a problem, so I changed it in the previous way. I ran it several times in the test environment without any problems. I thought it was all caused by the same problem, so I went online.

After going online, when I went to verify this function, Nima. . . The deadlock problem appeared before my eyes again.
Insert picture description here
I am panicked, why not this time? Is my code covered? Look at the git commit record and there is no. .

So we consulted the DBA, he said that replace into is not recommended, because in a large concurrency environment, there will definitely be deadlocks. Suggest that we use insert into… values… on duplicate key update… instead

So I changed it as suggested by the DBA. After going online again, no matter how concurrency is, there will be no deadlock.
Reason analysis, if you use replace into mysql, Gap lock and Next-key lock will be turned on by default, so even if transaction configuration is added, it will not work.

最后附上 insert into … on duplicate key update 介绍:
语法:
INSERT INTO tablename (field1,field2, field3, …) VALUES(value1, value2, value3, …) ON DUPLICATE KEY UPDATE field1=value1,field2=value2, field3=value3, …;

You can also use the following method (this supports batch insertion)
INSERT INTO TABLE (a,b,c) VALUES
(1,2,3),
(2,5,7),
(3,3,6),
(4, 8,2)
ON DUPLICATE KEY UPDATE a=VALUES(a), b=VALUES(b),c=VALUES(c);

Guess you like

Origin blog.csdn.net/huangdi1309/article/details/105663466