精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

淺談MySQL常見死鎖場景

數據庫和存儲 ? 來源:數據庫和存儲 ? 2024-03-21 14:10 ? 次閱讀

在之前的文章MySQL 常見死鎖場景 -- 并發(fā)Replace into導致死鎖介紹了由于二級索引 unique key 導致的 deadlock, 其實主鍵也是 unique 的, 那么同樣其實主鍵的 unique key check 一樣會導致死鎖.

主鍵 unique 的判斷在

row_ins_clust_index_entry_low => row_ins_duplicate_error_in_clust

對于普通的INSERT操作, 當需要檢查primary key unique時, 加 S record lock. 而對于Replace into 或者 INSERT ON DUPLICATE操作, 則加X record lock

這里check unique 的時候, 如果這里沒有這個 record 存在, 加在下一個 record上, 如果已經有一個 delete_mark record, 那么就加在這個 delete marked record 上.

例子 1

create table t1 (a int primary key);

# 然后有三個不 session:

session1: begin; insert into t1(a) values (2);

session2: insert into t1(a) values (2);

session3: insert into t1(a) values (2);

session1: rollback;

rollback 之前:

這個時候 session2/session3 會wait 在這里2 等待s record lock, 因為session1 執(zhí)行delete 時候會執(zhí)行row_update_for_mysql => lock_clust_rec_modify_check_and_lock

這里會給要修改的record 加x record lock

insert 的時候其實也給record 加 x record lock, 只不過大部分時候先加implicit lock, 等真正有沖突的時候觸發(fā)隱式鎖的轉換才會加上x lock

8d27b792-e72e-11ee-a297-92fbcf53809c.png

問題1: 這里為什么granted lock 里面 record 2 上面有x record lock 和 s record lock?

在session1 執(zhí)行 rollback 以后, session2/session3 獲得了s record lock, 在insert commit 時候發(fā)現死鎖, rollback 其中一個事務, 另外一個提交, 死鎖信息如下

8d3dfa66-e72e-11ee-a297-92fbcf53809c.png

這里看到 trx1 想要 x insert intention lock.

但是trx2 持有s next-key lock 和 trx1 x insert intention lock 沖突.

同時trx 也在等待 x insert intention lock, 這里從上面的持有Lock 可以看到 肯定在等待trx1 s next-key lock

問題: 等待的時候是 S gap lock, 但是死鎖的時候發(fā)現是 S next-key lock. 什么時候進行的升級?

這里問題的原因是這個 table 里面只有record 2, 所以這里認真看, 死鎖的時候是等待在 supremum 上的, 因為supremum 的特殊性, supremum 沒有gap lock, 只有 next-key lock

0: len 8; hex 73757072656d756d: asc supremum; // 這個是等在supremum 記錄

在 2 后面插入一個 3 以后, 就可以看到在record 3 上面是有s gap lock 并不是next-key lock, 如下圖:

8d43417e-e72e-11ee-a297-92fbcf53809c.png

那么這個 gap lock 是哪來的?

這里gap lock 是在 record 3 上的. 這個record 3 的s lock 從哪里來? session2/3 等待在record 2 上的s record lock 又到哪里去了?

這幾涉及到鎖升級, 鎖升級主要有兩種場景

insert record, 被next-record 那邊繼承鎖. 具體代碼 lock_update_insert

delete record(注意這里不是delete mark, 必須是purge 的物理delete), 需要將該record 上面的lock, 贈給next record上, 具體代碼 lock_update_delete

并且由于delete 的時候, 將該record 刪除, 如果有等待在該record 上面的record lock, 也需要遷移到next-key 上, 比如這個例子wait 在record 2 上面的 s record lock

另外對于wait 在被刪除的record 上的trx, 則通過 lock_rec_reset_and_release_wait(block, heap_no); 將這些trx 喚醒

具體看 InnoDB Trx lock

總結:

2 個trx trx2/trx3 都等待在primary key 上, 鎖被另外一個 trx1 持有. trx1 回滾以后, trx2 和 trx3 同時持有了該 record 的 s lock, 通過鎖升級又升級成下一個 record 的 GAP lock. 然后兩個 trx 同時插入的時候都需要獲得insert_intention lock(LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION); 就變成都想持有insert_intention lock, 被卡在對方持有 GAP S lock 上了.

例子 2

mysql> select * from t1;
+—-+
| a |
+—-+
| 2 |

| 3 |

+—-+

然后有三個不同 session:

session1: begin; delete from t1 where a = 2;

session2: insert into t1(a) values (2);

session3: insert into t1(a) values (2);

session1: commit;

commit之前

8d57c40a-e72e-11ee-a297-92fbcf53809c.png

這個時候session2/3 都在等待s record 2 lock, 等待時間是 innodb_lock_wait_timeout,

commit 之后

在session1 執(zhí)行 commit 以后, session2/session3 獲得到正在waiting的 s record lock, 在commit 的時候, 發(fā)現死鎖, rollback 其中一個事務, 另外一個提交, 死鎖信息如下

8d5c4426-e72e-11ee-a297-92fbcf53809c.png

trx1 等待x record lock, trx2 持有s record lock(這個是在session1 commit, session2/3 都獲得了s record lock)

不過這樣發(fā)現和上面例子不一樣的地方, 這里的record 都lock 在record 2 上, 而不是record 3, 這是為什么?

本質原因是這里的delete 操作是 delete mark, 并沒有從 btree 上物理刪除該record, 因此還可以保留事務的lock 在record 2 上, 如果進行了物理刪除操作, 那么這些record lock 都有遷移到next record 了

問題: 這里insert 操作為什么不是 insert intention lock?

比如如果是sk insert 操作就是 insert intention lock. 而這里是 s record lock?

8d76dea8-e72e-11ee-a297-92fbcf53809c.png

這里delete record 2 以后, 由于record 是 delete mark, 記錄還在, 因此insert 的時候會將delete mark record改成要寫入的這個record(這里不是可選擇優(yōu)化, 而是btree 唯一性, 必須這么做). 因此插入就變成 row_ins_clust_index_entry_by_modify

所以不是insert 操作, 因此就沒有 insert intention lock.

而sk insert 的時候是不允許將delete mark record 復用的, 因為delete mark record 可能會被別的readview 讀取到.

8d95d970-e72e-11ee-a297-92fbcf53809c.png

通過GDB + call srv_debug_loop() 可以讓GDB 將進程停留在 session1 提交, 但是session2/3 還沒有進入死鎖之前, 這個時候查詢performance_schema 可以看到session2/3 獲得了record 10 s lock. 這個lock 怎么獲得的呢?

這個和上述的例子一樣, 這里因為等的比較久了, 所以發(fā)生了purge, 因為record 2 被物理刪除了. 因此發(fā)生了鎖升級, record 2 上面的record 會轉給next-record, 這里next-record 是10,

總結:

和上一個例子基本類似.

2 個trx trx2/trx3 都等待在primary key 上的唯一性檢查上, 鎖被另外一個 trx1 持有. trx1 commit 以后, trx2 和 trx3 同時持有了該 record 的 s record lock, 然后由于 delete mark record 的存在, insert 操作變成 modify 操作, 因此就變成都想持有X record lock, 被卡在對方持有 S recordlock 上了.

審核編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • 死鎖
    +關注

    關注

    0

    文章

    25

    瀏覽量

    8066
  • MySQL
    +關注

    關注

    1

    文章

    801

    瀏覽量

    26439

原文標題:MySQL 常見死鎖場景-- 并發(fā)插入相同主鍵場景

文章出處:【微信號:inf_storage,微信公眾號:數據庫和存儲】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    淺談原理圖和PCB圖的常見錯誤

    淺談原理圖和PCB圖的常見錯誤
    發(fā)表于 08-12 13:04

    MySQL和MongoDB的對比

    中的文檔不需要具有相同的一組字段,數據的非規(guī)范化是常見的。 MongoDB還設計了高可用性和可擴展性,并提供了即用型復制和自動分片功能。術語和概念 MySQL中的許多概念在MongoDB中具有相近
    發(fā)表于 08-28 14:51

    藍牙低功耗常見的應用場景及架構

    淺談藍牙低功耗(BLE)的幾種常見的應用場景及架構
    發(fā)表于 06-15 09:51

    DIN中的死鎖避免和死鎖恢復

    DIN中的死鎖避免和死鎖恢復 由于存在占用資源者申請另一個資源的情形,在DIN中由于拓撲結構本身存在環(huán)狀路徑,所以
    發(fā)表于 02-23 14:47 ?901次閱讀
    DIN中的<b class='flag-5'>死鎖</b>避免和<b class='flag-5'>死鎖</b>恢復

    淺談易用性測試及GUI常見的測試要求

    淺談易用性測試及GUI常見的測試要求
    的頭像 發(fā)表于 06-29 10:15 ?2784次閱讀

    盤點MySQL常見問題及解答

    MySQL常見問題及答案匯總,MySQL是一種開放源代碼的關系型數據庫管理系統。數據庫按照數據結構來組織、存儲和管理數據的倉庫。每個數據庫都有一個或多個不同的 API 用于創(chuàng)建,訪問,管理,搜索和復制所保存的數據。
    的頭像 發(fā)表于 01-03 15:25 ?2463次閱讀

    常見MySQL高頻面試題

    在各類技術崗位面試中,似乎 MySQL 相關問題經常被問到。無論你面試開發(fā)崗位或運維崗位,總會問幾道數據庫問題。經常有小伙伴私信我,詢問如何應對 MySQL 面試題。其實很多面試題都是大同小異的,提前做準備還是很有必要的。本篇文章簡單說下幾個
    的頭像 發(fā)表于 02-08 16:05 ?2358次閱讀

    MySQL中的高級內容詳解

    之前兩篇文章帶你了解了 MySQL 的基礎語法和 MySQL 的進階內容,那么這篇文章我們來了解一下 MySQL 中的高級內容。 其他文章: 138 張圖帶你 MySQL 入門 47
    的頭像 發(fā)表于 03-11 16:55 ?2192次閱讀
    <b class='flag-5'>MySQL</b>中的高級內容詳解

    MySQL并發(fā)Replace into導致死鎖場景簡析

    在之前的文章 #issue 68021 MySQL unique check 問題中, 我們已經介紹了在 MySQL 里面, 由于唯一鍵的檢查(unique check), 導致 MySQL 在 Read Commit 隔離級別
    的頭像 發(fā)表于 06-13 10:56 ?1359次閱讀
    <b class='flag-5'>MySQL</b>并發(fā)Replace into導致<b class='flag-5'>死鎖</b><b class='flag-5'>場景</b>簡析

    通過GDB non-stop mode調試MySQL

    通過GDB non-stop mode 調試MySQL, 特別是用于復現死鎖場景, 需要按照一定的并發(fā)順序寫入才可以構造出來, 通過GDB non-stop mode 可以非常方便進行構造
    的頭像 發(fā)表于 09-25 10:34 ?600次閱讀
    通過GDB non-stop mode調試<b class='flag-5'>MySQL</b>

    Linux內核死鎖lockdep功能

    的編程思路,也不可能避免會發(fā)生死鎖。在Linux內核中,常見死鎖有如下兩種: 遞歸死鎖:如在中斷延遲操作中使用了鎖,和外面的鎖構成了遞歸死鎖
    的頭像 發(fā)表于 09-27 15:13 ?677次閱讀
    Linux內核<b class='flag-5'>死鎖</b>lockdep功能

    死鎖的產生因素

    一、死鎖的概念 操作系統中的死鎖是指: 如果在一個進程集合中的每個進程都在等待只能有該集合中的其它進程才能引起的事件,而無限期陷入僵持的局面稱為死鎖。 二、死鎖的產生因素 1、系統擁有
    的頭像 發(fā)表于 11-09 09:37 ?1164次閱讀
    <b class='flag-5'>死鎖</b>的產生因素

    死鎖的現象及原理

    原理 1.1 復現最簡單的死鎖 線程A占有鎖1,線程B占有鎖2;此時線程A想要獲取鎖2,但是鎖2已經被線程B占有, 此時線程A會休眠等待線程B釋放鎖2后,再去獲得鎖2。可以看到下面的場景,線程B想要獲取鎖1,結果線程B也休眠去了。這就導致
    的頭像 發(fā)表于 11-10 16:32 ?441次閱讀
    <b class='flag-5'>死鎖</b>的現象及原理

    死鎖的現象以及原理

    前言 本文將從0到1寫一個死鎖檢測組件。源碼:deadlock_success.c 組件如何放入自己的項目里?把代碼末兩個Debug部分刪除,在你的項目里添加下面兩句代碼即可使用死鎖檢測組件
    的頭像 發(fā)表于 11-13 16:30 ?518次閱讀
    <b class='flag-5'>死鎖</b>的現象以及原理

    java死鎖產生的條件

    Java死鎖是指多個線程因為互相等待對方釋放資源而無法繼續(xù)執(zhí)行的情況。當線程處于死鎖狀態(tài)時,程序會無限期地等待資源,無法繼續(xù)執(zhí)行下去,從而導致整個系統的停滯。要理解并避免Java死鎖的產生,首先需要
    的頭像 發(fā)表于 12-04 13:42 ?431次閱讀