How to troubleshoot and solve the Mysql deadlock problem

How to troubleshoot and solve the Mysql deadlock problem

There are many ways to query whether there is a locked table in Mysql, and only one of the most commonly used ones is introduced here.

1. View ongoing transactions

SELECT * FROM information_schema.INNODB_TRX

2. View the transactions that are being locked

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

3. View transactions waiting for locks

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

4. Query whether to lock the table

SHOW OPEN TABLES where In_use > 0;

When a deadlock occurs, these methods can query information related to the current deadlock.
5. View the log of the latest deadlock

show engine innodb status

Remove deadlock
If you need to remove the deadlock, there is the simplest and rude way, that is, after finding the process id, kill it directly.
View current processes in progress

show processlist
// 也可以使用
SELECT * FROM information_schema.INNODB_TRX;

The process id found by these two commands is the same.
Kill the process corresponding to the process id

kill id
verification (check if there is still a lock after killing)

SHOW OPEN TABLES where In_use > 0;

————————————————

foreword

A deadlock has occurred, how to troubleshoot and resolve it? This article will discuss this issue with you

  • Prepare the data environment
  • Simulated Deadlock Incident
  • Analyzing Deadlock Logs
  • Analyzing deadlock results

Environmental preparation

Database isolation level:

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

Autocommit off:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)

Table Structure:

//id是自增主键,name是非唯一索引,balance普通字段
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `balance` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

Data in the table:

img

simulate concurrency

Open two terminals to simulate the concurrency of transactions, the execution sequence and experimental phenomena are as follows:

img

1) Transaction A executes the update operation, and the update is successful

mysql> update  account  set balance =1000 where name ='Wei';
Query OK, 1 row affected (0.01 sec)

2) Transaction B executes the update operation, and the update is successful

mysql> update  account  set balance =1000 where name ='Eason';
Query OK, 1 row affected (0.01 sec)

3) Transaction A executes the insert operation and gets stuck~

mysql> insert into account values(null,'Jay',100);

img

At this time, you can use select * from information_schema.innodb_locks; to check the lock situation:

img

4) Transaction B executes the insert operation, and the insert is successful, while the insert of transaction A changes from blocking to deadlock error.

mysql> insert into account values(null,'Yan',100);
Query OK, 1 row affected (0.01 sec)

img

lock introduction

Before analyzing the deadlock log, let’s introduce the lock first, haha~

img

Mainly introduce the compatibility and lock mode types of locks:

Shared locks and exclusive locks

InnoDB implements standard row-level locks, including two types: shared locks (referred to as s locks) and exclusive locks (referred to as x locks).

  • Shared lock (S lock): Allows a lock-holding transaction to read a row.
  • Exclusive lock (X lock): Allows a lock-holding transaction to update or delete a row.

If transaction T1 holds the s lock of row r, when another transaction T2 requests the lock of r, it will do the following:

  • The s lock requested by T2 is immediately granted, and as a result, both T1 and T2 hold the s lock of row r
  • T2 requesting x lock cannot be granted immediately

If T1 holds the x lock of r, then T2's request for the x and s locks of r cannot be granted immediately, and T2 must wait for T1 to release the x lock, because the X lock is not compatible with any lock.

img

intent lock

  • Intention shared lock (IS lock): The transaction wants to obtain a shared lock for certain rows in a table
  • Intent exclusive lock (IX lock): The transaction wants to obtain an exclusive lock on certain rows in a table

For example: after transaction 1 adds an S lock on table 1, transaction 2 needs to add an IX lock if it wants to change a certain row record. Because it is incompatible, it needs to wait for the S lock to be released; if transaction 1 adds an IS lock to table 1 , the IX lock added by transaction 2 is compatible with the IS lock and can be operated, which realizes more fine-grained locking.

The compatibility of locks in the InnoDB storage engine is as follows:

img

Record Locks

  • A record lock is the simplest row lock, which only locks one row. For example: SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE
  • Record locks are always added to the index. Even if a table does not have an index, InnoDB will implicitly create an index and use this index to implement record locks.
  • Will block other transactions to insert, update, delete

Record the transaction data of the lock (keyword: lock_mode X locks rec but not gap), the record is as follows:

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` 
trx id 10078 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 6; hex 00000000274f; asc     'O;;
 2: len 7; hex b60000019d0110; asc        ;;

Gap Locks

  • A gap lock is a lock that is added between two indexes, or on the gap before the first index, or after the last index.
  • What is locked by gap lock is an interval, not just every piece of data in this interval.
  • Gap locks only prevent other transactions from being inserted into the gap, they do not prevent other transactions from obtaining a gap lock on the same gap, so gap x lock and gap s lock have the same effect.

The transaction data of the gap lock (keyword: gap before rec), the records are as follows:

RECORD LOCKS space id 177 page no 4 n bits 80 index idx_name of table `test2`.`account` 
trx id 38049 lock_mode X locks gap before rec
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 3; hex 576569; asc Wei;;
 1: len 4; hex 80000002; asc     ;;

Next-Key Locks

  • Next-key lock is a combination of record lock and gap lock, which refers to the lock added to a record and the gap in front of this record.

Insert Intention Lock (Insert Intention)

  • The insertion intention lock is a gap lock set before inserting a row of records. This lock releases a signal of an insertion mode, that is, when multiple transactions are inserted in the same index gap, if they are not inserted into the same position in the gap, they will not Need to wait for each other.
  • Assuming that there are index values ​​4 and 7, several different transactions are ready to insert 5 and 6, and each lock locks the gap between 4 and 7 with the insertion intention lock before obtaining the exclusive lock of the inserted row, but does not block The other party does not conflict because of the inserted row.

Transaction data looks like this:

RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`
trx id 8731 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000066; asc    f;;
 1: len 6; hex 000000002215; asc     " ;;
 2: len 7; hex 9000000172011c; asc     r  ;;...

Lock mode compatibility matrix (horizontal locks are held, vertical locks are being requested):

img

How to read the deadlock log?

show engine innodb status

You can use show engine innodb status to view the latest deadlock log. After execution, the deadlock log is as follows:

2023-04-11 00:35:55 0x243c
*** (1) TRANSACTION:
TRANSACTION 38048, ACTIVE 92 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
MySQL thread id 53, OS thread handle 2300, query id 2362 localhost ::1 root update
insert into account values(null,'Jay',100)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 177 page no 4 n bits 80 index idx_name of table `test2`.`account` 
trx id 38048 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 3; hex 576569; asc Wei;;
 1: len 4; hex 80000002; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 38049, ACTIVE 72 sec inserting, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
MySQL thread id 52, OS thread handle 9276, query id 2363 localhost ::1 root update
insert into account  values(null,'Yan',100)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 177 page no 4 n bits 80 index idx_name of table `test2`.`account` 
trx id 38049 lock_mode X locks gap before rec
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 3; hex 576569; asc Wei;;
 1: len 4; hex 80000002; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 177 page no 4 n bits 80 index idx_name of table `test2`.`account` 
trx id 38049 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

*** WE ROLL BACK TRANSACTION (1)

How do we analyze the above deadlock log?

first part

1) Find the keyword TRANSACTION, transaction 38048

img

2) View the SQL being executed

insert into account values(null,'Jay',100)

3) Waiting for lock release (WAITING FOR THIS LOCK TO BE GRANTED), insert intention exclusive lock (lock_mode X locks gap before rec insert intention waiting), ordinary index (idx_name), physical record (PHYSICAL RECORD), gap interval (unknown, Wei);

img

the second part

1) Find the keyword TRANSACTION, transaction 38049

img

2) View the SQL being executed

insert into account  values(null,'Yan',100)

3) HOLDS THE LOCK, gap lock (lock_mode X locks gap before rec), ordinary index (index idx_name), physical record (physical record), interval (unknown, Wei);

img

4) Waiting for the lock to be released (waiting for this lock to be granted), inserting the intention lock (lock_mode X insert intention waiting), on the ordinary index (index idx_name), physical record (physical record), gap interval (unknown, +∞) ;

img

5) Transaction 1 rolls back (we roll back transaction 1);

view log results

img

Check the log to get:

  • The insert intent exclusive lock that transaction A is waiting for (transaction A is the transaction 1 of the log, which is checked according to the insert statement), is in the arms of transaction B~
  • Transaction B holds a gap lock and is waiting for an insert intent exclusive lock

Here, some friends may have doubts,

  • What lock does transaction A hold? The log doesn't show it at all. What kind of insertion intention exclusive lock does it want to take?
  • What kind of gap lock did transaction B take? Why does it also take the insert intent lock?
  • How is the infinite loop of deadlock formed? At present, the log cannot see the composition of an infinite loop?

Let’s analyze the wave in detail in the next section, one by one~

deadlock analysis

Four elements of deadlock cycle

img

  • Mutual exclusion condition: Refers to the exclusive use of the allocated resources by the process, that is, a certain resource is only occupied by one process within a period of time. If there are other processes requesting resources at this time, the requester can only wait until the process that occupies the resources is used up and released.
  • Request and holding conditions: It means that a process has kept at least one resource, but has made a new resource request, and the resource has been occupied by other processes. At this time, the requesting process is blocked, but it still holds on to other resources it has obtained.
  • Non-deprivation condition: Refers to the resources that the process has acquired, which cannot be deprived before it is used up, and can only be released by itself when it is used up.
  • Loop waiting condition: when a deadlock occurs, there must be a process—a circular chain of resources, that is, P0 in the process set {P0, P1, P2,...,Pn} is waiting for a resource occupied by P1; P1 is waiting for resources occupied by P2, ..., Pn is waiting for resources already occupied by P0.

What lock does transaction A hold? What kind of insertion intention exclusive lock does it want to take?

For the convenience of recording, the example uses W to represent Wei, J to represent Jay, and E to represent Eason~

Let's first analyze the locking situation of the update statement in transaction A~

update  account  set balance =1000 where name ='Wei';

Gap lock:

  • The Update statement will add a gap lock in the left interval and a gap lock in the right interval to the name of the non-unique index (because there is only one record with name='Wei' in the current table, so there is no gap lock in the middle~), that is (E, W) and (W, +∞)
  • Why do gap locks exist? Because this is the database isolation level of RR, it is used to solve the problem of phantom reading~

record lock

  • Because name is an index, the update statement will definitely add W's record lock

Next-Key lock

  • Next-Key lock = record lock + gap lock, so the update statement has a Next-Key lock of (E, W]

To sum up, after transaction A executes the update statement, it will hold the lock:

  • Next-key Lock:(E,W]
  • Gap Lock :(W,+∞)

Let's analyze the locking situation of the insert statement in a wave of transaction A

insert into account values(null,'Jay',100);

Gap lock:

  • Because Jay (J is between E and W), it is necessary to request a gap lock with (E, W)

Insert Intention Lock (Insert Intention)

  • The insertion intent lock is a gap lock set before inserting a row of records. This lock releases a signal of an insertion mode, that is, transaction A needs to insert the intent lock (E, W)

Therefore, after the update statement and insert statement of transaction A are executed, it holds the Next-Key lock of (E, W], the Gap lock of (W, +∞), and wants to get the insertion intention of (E, W) Exclusive lock, the waiting lock matches the deadlock log, haha~

img

What gap lock does transaction B own? Why does it also take the insert intent lock?

In the same way, let's analyze a wave of transaction B, the lock analysis of the update statement:

update  account  set balance =1000 where name ='Eason';

Gap lock:

  • The Update statement will add the gap lock of the left interval and the gap lock of the right interval to the name of the non-unique index (because there is only one record of name='Eason' in the current table, so there is no gap lock in the middle~), that is (-∞ , E) and (E, W)

record lock

  • Because name is an index, the update statement will definitely add the record lock of E

Next-Key lock

  • Next-Key lock = record lock + gap lock, so the Update statement has a Next-Key lock of (-∞, E]

To sum up, after transaction B executes the update statement, it will hold the lock:

  • Next-key Lock:(-∞,E]
  • Gap Lock :(E,W)

Let's analyze the locking situation of the insert statement in wave B again

insert into account  values(null,'Yan',100);

Gap lock:

  • Because Yan (Y is after W), it is necessary to request a gap lock with (W,+∞)

Insert Intention Lock (Insert Intention)

  • The insertion intent lock is a gap lock set before inserting a row of records. This lock releases a signal of an insertion mode, that is, transaction A needs to insert the intent lock (W,+∞)

Therefore, after the update statement and insert statement of transaction B are executed, it holds the Next-Key lock of (-∞, E], the Gap lock of (E, W), and wants to get the gap of (W, + ∞) Lock, that is, inserting an intentional exclusive lock, the lock situation is also consistent with the deadlock log~

imgimg

Deadlock Truth Restoration

Next, let us restore the deadlock truth together haha

img

  • Transaction A executes the Update Wei statement, holds the Next-key Lock of (E, W], the Gap Lock of (W, +∞), and inserts successfully~
  • Transaction B executes the Update Eason statement, holds the Next-Key Lock of (-∞, E], the Gap Lock of (E, W), and the insertion is successful~
  • When transaction A executes the statement of Insert Jay, because it needs the insertion intention lock of (E, W), but (E, W) is in the arms of transaction B, so it is stuck~
  • When transaction B executes the statement of Insert Yan, because it needs the insertion intention lock of (W,+∞), but (W,+∞) is in the arms of transaction A, so it also gets stuck.
  • Transaction A holds (W, +∞) Gap Lock, waiting for (E, W) insertion intention lock, transaction B holds (E, W) Gap lock, waiting for (W,+∞) insertion intention Lock, so a closed loop of deadlock is formed (Gap lock and insertion intention lock will conflict, you can see the lock mode compatibility matrix introduced by the lock )
  • After transactions A and B form a deadlock closed loop, because of the underlying mechanism of Innodb, it will allow one of the transactions to give up resources, and the other transaction will execute successfully. This is why you see that transaction B is successfully inserted, but transaction A’s The insert shows Deadlock found ~

Summarize

Finally, when we encounter a deadlock problem, how should we analyze it?

  • Simulate a deadlock scenario
  • show engine innodb status; view deadlock log
  • Find deadlock SQL
  • SQL lock analysis, you can go to the official website to see this
  • Analyze deadlock logs (what locks are held, what locks are waiting for)
  • Familiar with the lock mode compatibility matrix, the compatibility matrix of locks in the InnoDB storage engine

MySQL adds a new user-ERROR 1045 (28000) solution

According to normal thinking, creating a user and setting a password should be done in one action. However, it is not.

Every time I create a MySQL user by looking for codes on the Internet. If it doesn't work, search for another paragraph.
Now I'm tired and have to write my own tutorial.

1. To connect to MySQL, the tool is to enter mysql on the terminal.
Generally speaking, several parameters can be set. The important thing is that -u represents the user, such as root or guest, -p represents the password, and -h represents the address. If it is localhost, it can be omitted.
Example mysql --user user --host localhost --port 3306 --password
Enter the password after pressing Enter.
Occasionally, you can log in directly using sudo mysql.

2. Select the mysql database.
use mysql;

3. Create a user, for example, if the user name is demo, use
create user demo;

4. Give the user permission.
grant all on *.* to 'demo'@'localhost' identified by 'password' ;
Here, all the permissions to operate the database are given to the demo, and the password is set to password.
If you want the user to create a new user and authorize it, use the add with grant option
grant all on *.* to 'demo'@'localhost' identified by 'password' with grant option;

5. Refresh.flush privileges;

Problem: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) I haven't used
mysql on this computer for a long time, and I need to connect to the database today, and an error is reported when I start the database:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

img

Solution:
After checking the information, you know, you should use the known user name and password to log in

mysql -u root -p

However, I forgot the password, and finally tried it out after several attempts:

img

Then change it to a common password without messing around:

img

I found that many tutorials are outdated, my version is Server version: 8.0.19 MySQL, the latest method:

img

mysql> use mysql;
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123';
mysql> flush privileges;

Exit verification to see if it is successful:

img

You can see that the password has been changed successfully.

Then, I pretended that the password was forgotten, and demonstrated the method of changing the password for the forgotten password:
Step 1: Shut down the Mysql service
First stop the mysql service. It can be closed by net stop mysql or task manager.

Operate with administrator privileges: (this is the first window)

img

img

Step 2: Skip Mysql password verification
and enter the command prompt (administrator login) operation, and enter the bin folder in the mysql directory. The difference between mysql8.0 and other versions is that you cannot directly use mysqld --skip-grant-tables to skip password login. Here we use mysqld -console --skip-grant-tables --shared-memory to skip permission verification.

img

There is no feedback after the input is executed, and a new administrator window is opened to execute again. (this is the second window)

After entering the directory, make sure you have shut down the Mysql service: net stop mysql

img

After closing the Mysql service, continue to operate in the D:\mysql-8.0.19-winx64\bin directory:
input

mysqld --console --skip-grant-tables --shared-memory

After entering this line of code, as shown below, we have successfully skipped the Mysql password login:

img

Step 3: Enter Mysql without a password.
After the above steps, open a cmd.exe running in administrator mode (this is the third window)

After entering the bin directory under mysql, log in directly to mysql

There is no need to open the mysql service through net start mysql

Enter the following code on the command line

d:
cd D:\mysql-8.0.19-winx64\bin(此处输入自己电脑上的安装目录)
mysql -u root -p

As shown in the picture:

img

At this time, it will display asking you to enter the password, press Enter directly, and you can successfully connect to Mysql.

img

Step 4: Set the login password to empty
Enter the code and set the password to empty (the password cannot be modified directly at this time, it must be set to empty first, otherwise an error will be reported)
Input:

use mysql; (使用mysql数据表)
update user set authentication_string='' where user='root';(将密码置为空)
quit; (然后退出Mysql)

The operation is as shown in the figure:

img

Step 5: Change your login password
This is divided into two parts

1. Close the first two cmd windows (must be closed!);
2. Enter the code in the third window;

net stop mysql(关闭mysql服务,虽然会显示没有开启服务,但是以防万一)
net start mysql(再打开mysql服务)

(Don't be too troublesome here, if the last mysql service is not closed, we still log in without a password)

The operation is as shown in the figure:

img

Then enter:

cd D:\mysql-8.0.19-winx64\bin (此处输入自己电脑上的安装目录)
mysql -u root -p

(The password will be displayed here, just press Enter, we have set it to empty in the fourth step)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'root'; (change password)

As shown in the picture:

img

The last step: Verify whether the password has been successfully modified
Enter:

quit(退出mysql)
mysql -u root -p

(Enter new password, log in again)

Graphic:

img

Reposted from: https://www.cnblogs.com/hanease/p/15955245.html

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/130477353