溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL數(shù)據(jù)庫之Purge死鎖問題的示例分析

發(fā)布時間:2021-07-24 14:04:57 來源:億速云 閱讀:206 作者:小新 欄目:編程語言

小編給大家分享一下MySQL數(shù)據(jù)庫之Purge死鎖問題的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

Purge死鎖

場景說明

MySQL數(shù)據(jù)庫之Purge死鎖問題的示例分析

Purge死鎖說明

表中存在記錄(unique key) 10,20,30,40 (且有 自增主鍵 ),現(xiàn)在刪除記錄 20 ,并且已經(jīng) 提交 了該事物。 purge 線程此時還 沒有回收 該記錄,且此時又 插入 新的記錄 20 。

+------+------+------+------+
orignal | 10 | 20 | 30 | 40 |
unique +------+------+------+------+
delete 20 +------+------+------+------+
| 10 | 20* | 30 | 40 | (20 : delete-mark)
and commit +------+^----^+------+------+
| |
non happen | +--insert new 20
|
Purge
# 自增主鍵圖中沒有給出

回顧插入過程 完整的插入過程如下:

假設(shè)現(xiàn)在有記錄 10,30,50,70 ;且為 unique key ,需要插入記錄 25 。

1. 找到 小于等于25的記錄 ,這里是 10

如果記錄中已經(jīng) 存在記錄25 ,且?guī)в?唯一性約束 ,則需要在 記錄25 上增加 S Gap-lock (purge的案例中,老 記錄20* 要加S lock的原因)

不直接報錯退出或者提示已存在的原因,是因為有可能之前的 記錄25 標(biāo)記為刪除( delete-mark ),然后等待 purge

如果 假設(shè) 這里 沒有S Gap-Lock ,此時 記錄30 上也 沒有鎖 的,按照下面的步驟,可以插入 兩個25 ,這樣就 破壞了唯一性約束

2. 找到 記錄10的下一條記錄 ,這里是 30

3. 判斷 下一條記錄30 上是否有鎖(如果有=25的情況,后面再討論)

判斷 30 上面如果 沒有鎖 ,則 可以插入

判斷 30 上面如果有 Record Lock ,則 可以插入

判斷 30 上面如果有 Gap Lock / Next-Key Lock ,則無法插入,因為鎖的范圍是 (10, 30) / (10, 30] ;在 30 上增加 insert intention lock (此時處于 waiting 狀態(tài)),當(dāng) Gap Lock / Next-Key Lock 釋放時,等待的事物(transaction)將被 喚醒 ,此時 記錄30 上才能獲得 insert intention lock ,然后再插入 記錄25

在這個場景中,新插入的記錄 20 ,和已經(jīng)存在的記錄 20* 相等,且?guī)в形ㄒ患s束,那此時就需要在記錄 20* 上增加 S lock(with gap)

演示

因為要模擬插入記錄 20* 的時候,老的 記錄20 要存在,所以使用debug版本,將 purge線程停掉 。

[root@MyServer ~]> mysqld-debug --version
mysqld-debug Ver 5.7.11-debug for linux-glibc2.5 on x86_64 (MySQL Community Server - Debug (GPL))
[root@MyServer ~]> mysqld-debug --datadir=/data/mysql_data/5.7.11/ &
[1] 1493
[root@MyServer ~]> netstat -tunlp | grep 3306
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 1493/mysqld-debug
--
-- 終端會話1
mysql> create table test_purge(a int auto_increment primary key, b int , unique key(b));
Query OK, 0 rows affected (0.20 sec)
mysql> insert into test_purge(b) values (10),(20),(30),(40);
Query OK, 4 rows affected (0.05 sec)
mysql> commit; -- autocommit=0 in my.cnf
Query OK, 0 rows affected (0.03 sec)
mysql> set global innodb_purge_stop_now=1;
-- show這個變量,結(jié)果還是off,這個不用管,purge線程已經(jīng)停止了
Query OK, 0 rows affected (0.00 sec)
mysql> begin;
mysql> delete from test_purge where b=20;
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.02 sec)
-- 終端會話2
mysql> select * from test_purge;
+---+------+
| a | b | -- 20的那條記錄已經(jīng)刪除,但是還沒有被purge(purge線程停止)
| 1 | 10 |
| 3 | 30 |
| 4 | 40 |
3 rows in set (0.00 sec)
mysql> insert into test_purge(b) values(20);
Query OK, 1 row affected (0.04 sec)
-- 終端會話3
mysql> show engine innodb status\G
-- ----------------省略其他輸出----------------
---TRANSACTION 9497, ACTIVE 19 sec
3 lock struct(s), heap size 1160, 3 row lock(s), undo log entries 1
MySQL thread id 3, OS thread handle 139922002294528, query id 26 localhost root cleaning up
TABLE LOCK table `burn_test`.`test_purge` trx id 9497 lock mode IX
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9497 lock mode S -- S lock (with gap)
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
-- heap no=3表示是第二個插入的記錄20
-- 且info bits為32,表示記錄被標(biāo)記刪除了
0: len 4; hex 80000014; asc ;; -- 記錄為20
1: len 4; hex 80000002; asc ;; -- 對應(yīng)的主鍵為2
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
-- heap no=4表示的是20的下一個記錄30
-- 且該記錄上也有S lock
0: len 4; hex 8000001e; asc ;;
1: len 4; hex 80000003; asc ;;
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9497 lock mode S locks gap before rec
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 -- heap no=6為新插入的記錄20,從隱式鎖提升為顯示鎖
0: len 4; hex 80000014; asc ;;
1: len 4; hex 80000005; asc ;;

1. 因為是唯一索引,需要做唯一性檢查,從老的記錄 20* 開始檢查(第一個小于等于自己的值),則此時 20* 上要加上一把 S lock ,然后往下檢查到第一個不相等的記錄,即 記錄30 ,然后退出,但是這個 記錄30 也要 加上S lock

2. 在插入 新的記錄20 的時候,發(fā)現(xiàn)下一條記錄30上有鎖,則自己插入的時的 隱式鎖 提升為 顯示鎖 (見插入步驟)

3. 目前鎖住的范圍是 (10,20], (20,30]

4. 新插入的記錄20本身是一把 S-Gap Lock (前面20*的有S lock了,由于是唯一索引,本身其實就不需要有記錄鎖了,有GAP就夠了)

所以記錄25無法插入(鎖等待)

mysql> insert into test_purge(b) values(25);
ERROR 1205 (HY000): Unknown error 1205 -- 等待了一段時間后,超時
---TRANSACTION 9508, ACTIVE 3 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1160, 1 row lock(s), undo log entries 1
MySQL thread id 5, OS thread handle 139922002560768, query id 46 localhost root update
insert into test_purge(b) values(25) -- 插入的25在等待
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9508 lock_mode X locks gap before rec insert intention waiting
------------------
TABLE LOCK table `burn_test`.`test_purge` trx id 9508 lock mode IX
---TRANSACTION 9503, ACTIVE 10 sec
MySQL thread id 7, OS thread handle 139922002028288, query id 44 localhost root cleaning up
TABLE LOCK table `burn_test`.`test_purge` trx id 9503 lock mode IX
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9503 lock mode S
1: len 4; hex 80000002; asc ;;
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9503 lock mode S locks gap before rec
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
1: len 4; hex 80000007; asc ;;

這個例子中出現(xiàn)了 鎖等待 ,就要 警惕 了,如果有 兩個事物相互等待 ,就是 死鎖 了

看完了這篇文章,相信你對“MySQL數(shù)據(jù)庫之Purge死鎖問題的示例分析”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI