MySQL數(shù)據(jù)庫(kù)之Purge死鎖問(wèn)題解析
Purge死鎖
場(chǎng)景說(shuō)明
Purge死鎖說(shuō)明
表中存在記錄(unique key) 10,20,30,40 (且有 自增主鍵 ),現(xiàn)在刪除記錄 20 ,并且已經(jīng) 提交 了該事物。 purge 線(xiàn)程此時(shí)還 沒(méi)有回收 該記錄,且此時(shí)又 插入 新的記錄 20 。
+------+------+------+------+ orignal | 10 | 20 | 30 | 40 | unique +------+------+------+------+ delete 20 +------+------+------+------+ | 10 | 20* | 30 | 40 | (20 : delete-mark) and commit +------+^----^+------+------+ | | non happen | +--insert new 20 | Purge # 自增主鍵圖中沒(méi)有給出
回顧插入過(guò)程 完整的插入過(guò)程如下:
假設(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的原因)
不直接報(bào)錯(cuò)退出或者提示已存在的原因,是因?yàn)橛锌赡苤暗?記錄25 標(biāo)記為刪除( delete-mark ),然后等待 purge
如果 假設(shè) 這里 沒(méi)有S Gap-Lock ,此時(shí) 記錄30 上也 沒(méi)有鎖 的,按照下面的步驟,可以插入 兩個(gè)25 ,這樣就 破壞了唯一性約束
2. 找到 記錄10的下一條記錄 ,這里是 30
3. 判斷 下一條記錄30 上是否有鎖(如果有=25的情況,后面再討論)
判斷 30 上面如果 沒(méi)有鎖 ,則 可以插入
判斷 30 上面如果有 Record Lock ,則 可以插入
判斷 30 上面如果有 Gap Lock / Next-Key Lock ,則無(wú)法插入,因?yàn)殒i的范圍是 (10, 30) / (10, 30] ;在 30 上增加 insert intention lock (此時(shí)處于 waiting 狀態(tài)),當(dāng) Gap Lock / Next-Key Lock 釋放時(shí),等待的事物(transaction)將被 喚醒 ,此時(shí) 記錄30 上才能獲得 insert intention lock ,然后再插入 記錄25
在這個(gè)場(chǎng)景中,新插入的記錄 20 ,和已經(jīng)存在的記錄 20* 相等,且?guī)в形ㄒ患s束,那此時(shí)就需要在記錄 20* 上增加 S lock(with gap)
演示
因?yàn)橐M插入記錄 20* 的時(shí)候,老的 記錄20 要存在,所以使用debug版本,將 purge線(xiàn)程停掉 。
[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 -- -- 終端會(huì)話(huà)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這個(gè)變量,結(jié)果還是off,這個(gè)不用管,purge線(xiàn)程已經(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) -- 終端會(huì)話(huà)2 mysql> select * from test_purge; +---+------+ | a | b | -- 20的那條記錄已經(jīng)刪除,但是還沒(méi)有被purge(purge線(xiàn)程停止) | 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) -- 終端會(huì)話(huà)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表示是第二個(gè)插入的記錄20 -- 且info bits為32,表示記錄被標(biāo)記刪除了 0: len 4; hex 80000014; asc ;; -- 記錄為20 1: len 4; hex 80000002; asc ;; -- 對(duì)應(yīng)的主鍵為2 Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 -- heap no=4表示的是20的下一個(gè)記錄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. 因?yàn)槭俏ㄒ凰饕?,需要做唯一性檢查,從老的記錄 20* 開(kāi)始檢查(第一個(gè)小于等于自己的值),則此時(shí) 20* 上要加上一把 S lock ,然后往下檢查到第一個(gè)不相等的記錄,即 記錄30 ,然后退出,但是這個(gè) 記錄30 也要 加上S lock
2. 在插入 新的記錄20 的時(shí)候,發(fā)現(xiàn)下一條記錄30上有鎖,則自己插入的時(shí)的 隱式鎖 提升為 顯示鎖 (見(jiàn)插入步驟)
3. 目前鎖住的范圍是 (10,20], (20,30]
4. 新插入的記錄20本身是一把 S-Gap Lock (前面20*的有S lock了,由于是唯一索引,本身其實(shí)就不需要有記錄鎖了,有GAP就夠了)
所以記錄25無(wú)法插入(鎖等待)
mysql> insert into test_purge(b) values(25); ERROR 1205 (HY000): Unknown error 1205 -- 等待了一段時(shí)間后,超時(shí) ---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 ;;
這個(gè)例子中出現(xiàn)了 鎖等待 ,就要 警惕 了,如果有 兩個(gè)事物相互等待 ,就是 死鎖 了
總結(jié)
以上所述是小編給大家介紹的MySQL數(shù)據(jù)庫(kù)之Purge死鎖問(wèn)題解析,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- MySQL數(shù)據(jù)庫(kù)表被鎖、解鎖以及刪除事務(wù)詳解
- MYSQL數(shù)據(jù)庫(kù)Innodb?引擎mvcc鎖實(shí)現(xiàn)原理
- MySQL數(shù)據(jù)庫(kù)事務(wù)與鎖深入分析
- MySQL數(shù)據(jù)庫(kù)鎖機(jī)制原理解析
- MySQL數(shù)據(jù)庫(kù)的一次死鎖實(shí)例分析
- mysql數(shù)據(jù)庫(kù)鎖的產(chǎn)生原因及解決辦法
- mysql 數(shù)據(jù)庫(kù)死鎖原因及解決辦法
- Mysql 數(shù)據(jù)庫(kù)死鎖過(guò)程分析(select for update)
- Mysql數(shù)據(jù)庫(kù)鎖定機(jī)制詳細(xì)介紹
- MySQL 數(shù)據(jù)庫(kù)鎖的實(shí)現(xiàn)
相關(guān)文章
Spring?Security圖形驗(yàn)證碼的實(shí)現(xiàn)代碼
本文介紹了如何在SpringSecurity自定義認(rèn)證中添加圖形驗(yàn)證碼,首先需要在maven中添加相關(guān)依賴(lài)并創(chuàng)建驗(yàn)證碼對(duì)象,然后通過(guò)Spring的HttpSessionSessionStrategy對(duì)象將驗(yàn)證碼存儲(chǔ)到Session中,感興趣的朋友跟隨小編一起看看吧2024-10-10詳解spring batch的使用和定時(shí)器Quart的使用
spring Batch是一個(gè)基于Spring的企業(yè)級(jí)批處理框架,它通過(guò)配合定時(shí)器Quartz來(lái)輕易實(shí)現(xiàn)大批量的數(shù)據(jù)讀取或插入,并且全程自動(dòng)化,無(wú)需人員管理2017-08-08Netty學(xué)習(xí)教程之Netty與Marshalling結(jié)合發(fā)送對(duì)象
Netty是由JBOSS提供的一個(gè)Java開(kāi)源框架,之前已經(jīng)給大家簡(jiǎn)單介紹了一些基礎(chǔ)與使用,下面這篇文章主要給大家介紹了關(guān)于Netty與Marshalling結(jié)合發(fā)送對(duì)象的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-05-05Java進(jìn)程內(nèi)緩存框架EhCache詳解
這篇文章主要介紹了Java進(jìn)程內(nèi)緩存框架EhCache,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2021-12-12SpringBoot 項(xiàng)目添加 MDC 日志鏈路追蹤的執(zhí)行流程
日志鏈路追蹤就是將一個(gè)標(biāo)志跨線(xiàn)程進(jìn)行傳遞,在一般的小項(xiàng)目中也就是在你新起一個(gè)線(xiàn)程的時(shí)候,或者使用線(xiàn)程池執(zhí)行任務(wù)的時(shí)候會(huì)用到,比如追蹤一個(gè)用戶(hù)請(qǐng)求的完整執(zhí)行流程,本文給大家介紹SpringBoot MDC 日志鏈路追蹤的代碼,感興趣的朋友一起看看吧2021-06-06過(guò)濾器 和 攔截器的 6個(gè)區(qū)別(別再傻傻分不清了)
這篇文章主要介紹了過(guò)濾器 和 攔截器的 6個(gè)區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06