Mysql死锁(dead lock)与锁等待(lock wait)的出现解决!
Mysql死锁(dead lock)与锁等待(lock wait)的出现解决!
很多人都分不清死锁和锁等待的区别,也有不同IT口的人叫法的差异。在运维侧:
死锁最明显的特征是会自动解开,是需要我们去事后解决逻辑缺陷。
锁等待则是业务卡住了(一般是某个大事务还在执行,或有事务没提交),需要杀掉持有锁的进城让业务正常进行
做几个实验详细演示一下。
表结构及数据情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
mysql> desc ttt; + -------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | + -------+-------------+------+-----+---------+-------+ | x | int (11) | NO | PRI | NULL | | | y | datetime | YES | | NULL | | | z | varchar (10) | YES | | NULL | | + -------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> select * from ttt; + ---+---------------------+------+ | x | y | z | + ---+---------------------+------+ | 1 | 2023-05-30 23:50:13 | 123 | | 2 | 2023-04-26 17:58:18 | av3 | | 3 | 2023-05-30 22:52:35 | at | | 4 | 2023-04-26 17:58:29 | attt | | 5 | 2023-05-30 22:52:55 | zxz | + ---+---------------------+------+ 5 rows in set (0.00 sec) |
死锁(dead lock)
上文说了,死锁会自动解除,这里主要展示一下怎么追查。这里就不演示具体执行顺序了
前台报错
session1,这个先持有
1
2
3
4
5
6
7
8
9
10
11
|
mysql> begin ; Query OK, 0 rows affected (0.00 sec) mysql> update ttt set y=now() where x=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> update ttt set y=now() where x=3; Query OK, 1 row affected (7.04 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> |
session2,这个来跳出错误
1
2
3
4
5
6
7
8
9
10
|
mysql> begin ; Query OK, 0 rows affected (0.00 sec) mysql> update ttt set y=now() where x=3; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> update ttt set y=now() where x=1; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction mysql> |
事后追查
innodb status的last dead lock只会记录上一次,建议是使用innodb_print_all_deadlocks参数,将记录打印到error.log中,该参数默认为off,可以动态修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
mysql> show variables like '%innodb_print_all_deadlocks%' ; + ----------------------------+-------+ | Variable_name | Value | + ----------------------------+-------+ | innodb_print_all_deadlocks | OFF | + ----------------------------+-------+ 1 row in set (0.00 sec) mysql> set global innodb_print_all_deadlocks= on ; Query OK, 0 rows affected (0.00 sec) mysql> show variables like '%innodb_print_all_deadlocks%' ; + ----------------------------+-------+ | Variable_name | Value | + ----------------------------+-------+ | innodb_print_all_deadlocks | ON | + ----------------------------+-------+ 1 row in set (0.00 sec) |
innodb status
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
show engine innodb status; ********* ------------------------ LATEST DETECTED DEADLOCK ------------------------ 2023-05-30 22:42:09 0x7f9fd41ba700 *** (1) TRANSACTION : TRANSACTION 5454, ACTIVE 26 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 18, OS thread handle 140324434298624, query id 440 localhost root updating update ttt set y=now() where x=3 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 23 page no 3 n bits 80 index PRIMARY of table `ddd`.`ttt` trx id 5454 lock_mode X locks rec but not gap waiting Record lock, heap no 10 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000003; asc ;; 1: len 6; hex 00000000154f; asc O;; 2: len 7; hex 390000014e0110; asc 9 N ;; 3: len 5; hex 99b03d6a76; asc =jv;; 4: len 2; hex 6174; asc at ;; *** (2) TRANSACTION : TRANSACTION 5455, ACTIVE 15 sec starting index read mysql tables in use 1, locked 1 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 20, OS thread handle 140324435109632, query id 441 localhost root updating update ttt set y=now() where x=1 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 23 page no 3 n bits 80 index PRIMARY of table `ddd`.`ttt` trx id 5455 lock_mode X locks rec but not gap Record lock, heap no 10 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000003; asc ;; 1: len 6; hex 00000000154f; asc O;; 2: len 7; hex 390000014e0110; asc 9 N ;; 3: len 5; hex 99b03d6a76; asc =jv;; 4: len 2; hex 6174; asc at ;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 23 page no 3 n bits 80 index PRIMARY of table `ddd`.`ttt` trx id 5455 lock_mode X locks rec but not gap waiting Record lock, heap no 7 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000001; asc ;; 1: len 6; hex 00000000154e; asc N;; 2: len 7; hex 380000014d0110; asc 8 M ;; 3: len 5; hex 99b03d6a6b; asc =jk;; 4: len 3; hex 313233; asc 123;; *** WE ROLL BACK TRANSACTION (2) ******** |
error.log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
[root@mysql57-1 data]# tail -100f mysql57-1.err 2023-05-25T07:42:37.677851Z 14 [Note] Access denied for user 'root' @ 'localhost' (using password : YES) 2023-05-25T07:44:15.360390Z 15 [Note] Access denied for user 'roo' @ 'localhost' (using password : YES) 2023-05-25T07:44:28.477560Z 16 [Note] Access denied for user 'roo' @ 'localhost' (using password : YES) 2023-05-30T14:53:00.101403Z 22 [Note] InnoDB: Transactions deadlock detected, dumping detailed information. 2023-05-30T14:53:00.101475Z 22 [Note] InnoDB: *** (1) TRANSACTION : TRANSACTION 5458, ACTIVE 25 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 21, OS thread handle 140324434298624, query id 473 localhost root updating update ttt set y=now() where x=5 2023-05-30T14:53:00.101516Z 22 [Note] InnoDB: *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 23 page no 3 n bits 80 index PRIMARY of table `ddd`.`ttt` trx id 5458 lock_mode X locks rec but not gap waiting Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000005; asc ;; 1: len 6; hex 000000001553; asc S;; 2: len 7; hex 3b00000130036d; asc ; 0 m;; 3: len 5; hex 99b03d6d32; asc =m2;; 4: len 3; hex 7a787a; asc zxz;; 2023-05-30T14:53:00.101718Z 22 [Note] InnoDB: *** (2) TRANSACTION : TRANSACTION 5459, ACTIVE 10 sec starting index read mysql tables in use 1, locked 1 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 22, OS thread handle 140324435109632, query id 474 localhost root updating update ttt set y=now() where x=3 2023-05-30T14:53:00.101748Z 22 [Note] InnoDB: *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 23 page no 3 n bits 80 index PRIMARY of table `ddd`.`ttt` trx id 5459 lock_mode X locks rec but not gap Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000005; asc ;; 1: len 6; hex 000000001553; asc S;; 2: len 7; hex 3b00000130036d; asc ; 0 m;; 3: len 5; hex 99b03d6d32; asc =m2;; 4: len 3; hex 7a787a; asc zxz;; 2023-05-30T14:53:00.101912Z 22 [Note] InnoDB: *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 23 page no 3 n bits 80 index PRIMARY of table `ddd`.`ttt` trx id 5459 lock_mode X locks rec but not gap waiting Record lock, heap no 10 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000003; asc ;; 1: len 6; hex 000000001552; asc R;; 2: len 7; hex 3a0000012e03d1; asc : . ;; 3: len 5; hex 99b03d6d23; asc =m#;; 4: len 2; hex 6174; asc at ;; 2023-05-30T14:53:00.102084Z 22 [Note] InnoDB: *** WE ROLL BACK TRANSACTION (2) |
锁等待(lock wait)
1个参数
innodb_lock_wait_timeout
行锁等待的时间,如果超过这个时间,session2(后发起那个)会自动跳出
session1
1
2
3
4
5
6
7
|
mysql> begin ; Query OK, 0 rows affected (0.00 sec) mysql> update ttt set y=now() where x=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 |
session2
1
2
|
mysql> update ttt set y=now() where x=1; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
怎么处理
省略构造锁
通过information_schema.innodb_lock_waits视图获得锁等待的关系
1
2
3
4
5
6
7
|
mysql> select * from information_schema.innodb_lock_waits; + -------------------+-------------------+-----------------+------------------+ | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + -------------------+-------------------+-----------------+------------------+ | 5467 | 5467:23:3:7 | 5466 | 5466:23:3:7 | + -------------------+-------------------+-----------------+------------------+ 1 row in set , 1 warning (0.00 sec) |
再结合information_schema.innodb_trx视图得到语句和线程ID
这里提供一个sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query, b.trx_autocommit_non_locking FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id; mysql> SELECT r.trx_id waiting_trx_id, -> r.trx_mysql_thread_id waiting_thread, -> r.trx_query waiting_query, -> b.trx_id blocking_trx_id, -> b.trx_mysql_thread_id blocking_thread, -> b.trx_query blocking_query, -> b.trx_autocommit_non_locking -> FROM information_schema.innodb_lock_waits w -> INNER JOIN information_schema.innodb_trx b ON -> b.trx_id = w.blocking_trx_id -> INNER JOIN information_schema.innodb_trx r ON -> r.trx_id = w.requesting_trx_id; + ----------------+----------------+----------------------------------+-----------------+-----------------+----------------+----------------------------+ | waiting_trx_id | waiting_thread | waiting_query | blocking_trx_id | blocking_thread | blocking_query | trx_autocommit_non_locking | + ----------------+----------------+----------------------------------+-----------------+-----------------+----------------+----------------------------+ | 5470 | 22 | update ttt set y=now() where x=1 | 5466 | 26 | NULL | 0 | + ----------------+----------------+----------------------------------+-----------------+-----------------+----------------+----------------------------+ 1 row in set , 1 warning (0.00 sec) |
再对blocking thread的状态进行确认,然后kill
1
2
3
4
5
6
7
|
mysql> select * from information_schema.PROCESSLIST where id=26; + ----+------+-----------+------+---------+------+-------+------+ | ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO | + ----+------+-----------+------+---------+------+-------+------+ | 26 | root | localhost | ddd | Sleep | 1221 | | NULL | + ----+------+-----------+------+---------+------+-------+------+ 1 row in set (0.00 sec) |
杀线程
1
2
|
mysql> kill 26; Query OK, 0 rows affected (0.00 sec) |
级联锁或大量锁
这里构造一个多个争用的情况。
session1,线程id为27,这个先发起
1
2
3
4
5
6
7
|
mysql> begin ; Query OK, 0 rows affected (0.00 sec) mysql> update ttt set y=now() where x=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 |
session,线程id为22,第二个发起
1
|
mysql> update ttt set y=now() where x=1; |
session3,线程id为28,最后一个发起
1
|
mysql> update ttt set y=now(); |
锁关系情况
1
2
3
4
5
6
7
8
9
|
mysql> select * from information_schema.innodb_lock_waits; + -------------------+-------------------+-----------------+------------------+ | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + -------------------+-------------------+-----------------+------------------+ | 5479 | 5479:23:3:7 | 5478 | 5478:23:3:7 | | 5479 | 5479:23:3:7 | 5473 | 5473:23:3:7 | | 5478 | 5478:23:3:7 | 5473 | 5473:23:3:7 | + -------------------+-------------------+-----------------+------------------+ 3 rows in set , 1 warning (0.01 sec) |
查询sql的展示情况
1
2
3
4
5
6
7
8
|
mysql> SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query, b.trx_autocommit_non_locking FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id; + ----------------+----------------+----------------------------------+-----------------+-----------------+----------------------------------+----------------------------+ | waiting_trx_id | waiting_thread | waiting_query | blocking_trx_id | blocking_thread | blocking_query | trx_autocommit_non_locking | + ----------------+----------------+----------------------------------+-----------------+-----------------+----------------------------------+----------------------------+ | 5479 | 28 | update ttt set y=now() | 5478 | 22 | update ttt set y=now() where x=1 | 0 | | 5479 | 28 | update ttt set y=now() | 5473 | 27 | NULL | 0 | | 5478 | 22 | update ttt set y=now() where x=1 | 5473 | 27 | NULL | 0 | + ----------------+----------------+----------------------------------+-----------------+-----------------+----------------------------------+----------------------------+ |
这个时候一般的做法是先找到最多的那个blocking_thread
确认他的进程状态后来考虑是否杀
如果他是活动的thread,在干活,就可以删掉释放资源。
如果他是非活动,就要看他这个thread的blocking_thread,找到活动持有资源的,来杀掉。
当然也有执行了完了不提交的情况,innodb_trx的trx_autocommit_non_locking列的值就是为了标记是否是提交了。0表示没有提交。
到此这篇关于mysql死锁(dead lock)与锁等待(lock wait)的出现解决的文章就介绍到这了。
学习资料见知识星球。
以上就是今天要分享的技巧,你学会了吗?若有什么问题,欢迎在下方留言。
快来试试吧,小琥 my21ke007。获取 1000个免费 Excel模板福利!
更多技巧, www.excelbook.cn
欢迎 加入 零售创新 知识星球,知识星球主要以数据分析、报告分享、数据工具讨论为主;
1、价值上万元的专业的PPT报告模板。
2、专业案例分析和解读笔记。
3、实用的Excel、Word、PPT技巧。
4、VIP讨论群,共享资源。
5、优惠的会员商品。
6、一次付费只需99元,即可下载本站文章涉及的文件和软件。
共有 0 条评论