主頁 > 軟體設計 > 一文搞懂鎖知識

一文搞懂鎖知識

2021-10-10 08:56:50 軟體設計

一位風塵仆仆的男子走了過來,對我說:小伙子,我看你簡歷上寫的精通mysql,那我就問問你mysql的知識吧!

我:好的(千萬別多問,千萬別多問~~)

面試官:對mysql鎖了解的多嗎?

我:還行(其實就是很好),

面試官:那好,那我接下來主要問鎖相關的知識

我:好的好的(放馬過來吧,我也就是客氣一下,)

面試官: mysql支持哪些級別的鎖?
我:支持庫鎖、表鎖、行鎖,

面試官:那先說說庫鎖吧,鎖庫有幾種方式?

我:兩種,分別是FTWRL(Flush tables with read lock)和 set global readonly=true

面試官:這兩種有什么區別?

我:首先不管是誰,只要鎖庫了,那么整個庫都處于只讀狀態,所有的更新操作都將被阻塞,FTWRL模式風險稍微小點,如果客戶端例外斷開后,FTWRL鎖會自動釋放,但是global readonly=true不會自動釋放鎖,

面試官:那myisam和innodb的鎖有什么區別,

我:myisam不支持行鎖,只支持表級的鎖,innodb支持更細粒度的行鎖,
面試官:表級鎖使用過嗎?

我:沒有用過,表鎖性能差,

面試官:那你知道MDL鎖嗎?

我:了解,MDL(metadata lock)鎖是server層的鎖,表級鎖,它是隱式的,不需要顯式的使用,mysql每次讀寫資料時(insert、update、select、delete)都要先去獲取MDL讀鎖,只有獲取到了MDL讀鎖,才能進行接下來的操作,否則阻塞,其中MDL讀鎖之間是共享的,當對資料庫進行表結構變更的時候,會獲取MDL寫鎖,MDL寫鎖和任何MDL鎖都是互斥的,不管是MDL讀鎖還是MDL寫鎖,

面試官:那MDL鎖的作用是什么?

我:MDL鎖是為了解決DDL和DML之間沖突的問題,

  1. 假設事務A先查詢得到一個資料,然后事務B執行了欄位修改,那么事務A再次去查的時候,發現資料對不上了,

  1. 事務A先更新資料未提交,事務B修改欄位提交,slave就會先修改欄位,再更新資料,那么就會有問題

當使用了MDL鎖后,DDL操作必須要先獲得MDL寫鎖,我們知道寫鎖和寫鎖,寫鎖和讀鎖是沖突的,那么在DDL之前如果有任何查詢或者更新,都必須要阻塞等待,不會讓DDL執行的,從而解決了沖突問題,

面試官:那有了MDL鎖,在線DDL是不是就很安全?

我:不一定,

假設session1先執行查詢,但是不提交,session2緊接著執行添加欄位的DDL,最后session3再執行查詢,此時會發現session2和session3都是阻塞的,如果后面還來了sessionN的查詢,那么都將阻塞,嚴重時將造成大量執行緒阻塞,

面試官:那你能解釋下為什么這種情況下會阻塞嗎?

我:首先MDL鎖一定是在事務提交后才釋放的,session1在執行查詢后,并沒有commit,那么MDL讀鎖是沒有釋放的,session2緊接著執行DDL,執行DDL是要獲取MDL寫鎖的,由于寫鎖和讀鎖是互斥的,那么session2是卡住的,它在等待session1釋放讀鎖,session3在session2之后執行的,此時session3是需要一個讀鎖的,但是由于獲取鎖是有先后順序的,它們要排隊,并且寫鎖的優先級要高于讀鎖,這也是為什么session3會卡住,

面試官:所以是session1執行commit之后,然后session2先執行完,最后session3先執行完?我剛試了下你的例子,看著好像session2和session3幾乎同時運行完,你能否具體說說為什么呢?(看你進不進坑)

我:(想給我挖坑,沒門),不是的,并不是session2先執行完,其實是session3先執行完,但是session2會先獲得MDL寫鎖,由于session3沒有顯式的開啟一個事務,那么session3默認執行完畢之后自動commit,所以在session1 commit之后,看起來像session2和session3幾乎同時進行的,如果讓session3顯式的開啟事務,就能發現運行的細節了,

這樣當session1 commit之后可以發現session3先執行,session2依然是卡住的,只有當session3 commit之后,發現session2才能運行,所以真實情況應該是session3先執行,然后session2,

面試官:那這和你上面說的獲取MDL鎖排隊的問題是不是矛盾了?

我:不矛盾,這其實涉及到online DDL的知識了,我們知道mysql支持在線DDL,不阻塞用戶操作,當執行一個DDL,它的流程大概是這樣的:

  1. 拿MDL寫鎖
  2. 降級成MDL讀鎖
  3. 真正做DDL
  4. 升級成MDL寫鎖
  5. 釋放MDL鎖

其中session2在拿到MDL寫鎖后,會降級成MDL讀鎖,降級后,session3拿到MDL讀鎖,然后執行select,但是沒有commit,這樣MDL讀鎖就沒釋放,然后session2在升級成MDL寫鎖的時候因為session3沒釋放讀鎖從而導致session2阻塞,

面試官:(這小子不錯呀),那你知道為什么DDL程序中1-2要降級,而3-4又要升級嗎?

我:(早知道就要問,還好我有準備),

首先在MDL寫鎖期間,干的事就是創建臨時的frm和idb檔案,這個程序要安全,是排他的,同時這個程序也是快速的,在臨時檔案創建好之后,就不需要排他了,那么就降級為讀鎖,支持正常的增刪改查,這也是為什么DDL支持online的原因之一,在新的資料檔案寫好之后,要替換老的資料檔案,這個程序要安全,所以在3執行完后,會嘗試升級成MDL寫鎖,這個程序也是快速的,也是支持online DDL的原因之二,

面試官:我們知道InnoDB支持行級鎖,行鎖還分兩類你知道嗎?

我:知道,S(共享鎖)和X(排他鎖),S鎖和S鎖是共享的,X鎖和任意鎖互斥,

面試官:既然X鎖和任意鎖互斥,那么如果存在兩個事務,事務A更新資料后,不提交,那么事務B去查詢這條資料是不是就阻塞?

我:不會的,因為InnoDB支持MVCC(多版本控制),當一個事務執行查詢的時候,它可以通過undo log查詢到一個快照,這樣就不用鎖,

面試官:那你知道IS(意向共享鎖)和IX(意向排他鎖)嗎?

我:首先它倆都是表級別的鎖,因為InnoDB是支持行鎖的,當某些行已經上了X鎖之后,再想對這個表上鎖的話,就得確認當前表中沒有任何X鎖,在沒有意向鎖的情況下,就得一行一行去判斷,這樣效率會非常低下,在有了意向鎖之后,就不需要一行一行判斷了,舉個例子:

select * from user where id=1 for update;

當一個事務對id=1這行資料上了X鎖之后,就會對user表也加一個IX鎖,

LOCK TABLES user READ;

這時想要給表加上讀鎖,但是發現表上有IX鎖,所以會阻塞無法執行,類似的如果一個事務對一行資料加上共享鎖

select * from user where id=1 lock in share mode;

就會給對應的表加上IS鎖,這時候如果執行

LOCK TABLES user WRITE;

也會因為表上有IS鎖而阻塞,

面試官:那我們來聊聊行鎖吧,InnoDB支持哪些行鎖?

我:有記錄鎖(Record Lock)、間隙鎖(Gap Lock)、Next-Key Lock

面試官:假設有一張表,表里有10條記錄,還有個欄位user_id,并且user_id是普通索引,

+----+---------+
| id | user_id |
+----+---------+
|  1 |      10 |
|  2 |      20 |
|  3 |      30 |
|  4 |      40 |
|  5 |      50 |
|  6 |      60 |
|  7 |      70 |
|  8 |      80 |
|  9 |      90 |
| 10 |     100 |
+----+---------+

如果事務A執行:

SELECT * FROM user WHERE user_id=50 FOR UPDATE;

緊接著事務B執行下面的sql會發生什么?:

INSERT INTO user set user_id=45;

我:阻塞,

面試官:能說下原因嗎?

我:因為InnoDB的Next-Key Lock演算法,不僅僅會鎖住user_id=50這條記錄,還會鎖住50左右的間隙,Next-Key Lock鎖定的范圍是左開右閉的,那么理論上最終(40,50],(50,60]的區間資料會被鎖定,

由于要插入的45在40-50之間,所以就會發生阻塞,

面試官:那按照你說的區間鎖法,是包含60這條資料的是吧,所以如果插入一條60的資料,就會發生阻塞?

INSERT INTO user set user_id=60;

我:其實不會,這里涉及到next key lock的優化,在等值查詢中,向右遍歷時且最后一個值不滿足等值條件的時候,Next-Key Lock會退化為Gap Lock,所以對于(50,60]這個區間最侄訓降級為(50,60),那么60這條資料就不會被鎖住,是可以插入成功的,

面試官:那40這條資料是不在這個鎖區間的,所以可以插入40這條資料?

INSERT INTO user set user_id=40;

我:其實也不會,40這條資料的插入也會阻塞,首先對于非聚集索引user_id它的葉子節點一定是排序的,大概就像(40,4),(50,5)這樣,其次因為主鍵id是自增的,那么對于再插入一條40的資料,它的主鍵id一定是大于4的,就目前10條資料來說,下一次插入的id肯定是11,那(40,11)這條資料肯定是要在(40,4)后面的,這樣的話,就落入到了間隙鎖中,所以會阻塞,其實上面60那條資料可以插入也是同樣的道理,

面試官:那如果我一開始不用select for update了,而用select lock in share mode,那么所有的插入會有什么變化嗎?

我:沒有變化,還是一樣,因為插入需要X鎖,X鎖和任何鎖都互斥,

面試官:如果user_id不是普通索引而是唯一索引,那會有什么變化?

我:當索引是唯一索引時,那么就會發生降級,Next Key Lock會降級成Record Lock,最終只會鎖住50這條記錄,

面試官:如果user_id沒有索引怎么辦?

我:那就所有的記錄都會鎖上,任何的插入都會阻塞,

面試官:那你知道為什么要有間隙鎖這個東西嗎?

我:為了解決幻讀,比如當事務A執行以下查詢時:

SELECT * FROM user WHERE id>=9 for update

應該回傳兩條記錄(id=9和id=10),這時候如果另一個事務B執行

INSERT INTO user set user_id=110;

在沒有間隙鎖的情況下,那么事務A再次查詢會發現多了一條記錄,就出現了幻讀,如果有了間隙鎖,那么[9,+∞)這個區間都會被鎖住,事務B的插入就會阻塞,但是只有在事務的隔離級別設定成可重復讀的時候,才支持間隙鎖,

面試官:如果某個上了鎖的事務一直不提交,那么后面需要獲取相關鎖的事務就會阻塞,這樣會有什么問題?

我:如果阻塞的事務越來越多,那么阻塞的執行緒也會越來越多,嚴重時會造成連接池滿了,mysql不能提供服務了,但是InnoDB支持阻塞超時后,會自動放棄這個等待鎖的sql命令,這個值默認是50s,

+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50    |
+--------------------------+-------+

面試官看了看我:那你知道AUTO-INC Locking嗎?

我:知道,自增長鎖,在InnoDB引擎中,每個表都會維護一個表級別的自增長計數器,當對表進行插入的時候,會通過以下的命令來獲取當前的自增長的值,

SELECT MAX(auto_inc_col)  FROM user FOR UPDATE;

插入操作會在這個基礎上加1得到即將要插入的自增長id,

面試官:我們知道事務中的鎖是在事務提交后才釋放的,那么在更新自增長id后,當事務沒來及提交,其它的事務獲取自增長id就要等待嗎?這樣的話效率是不是有點低?

我:不用等待的,為了提高插入性能,自增長的鎖不會等到事務提交之后才釋放,而是在相關插入sql陳述句完成后立刻就釋放的,這也是為什么一些事務回滾之后,發現id不連續的原因:

select * from user;
+----+---------+
| id | user_id |
+----+---------+
| .. |      .. |
|  9 |      90 |
| 10 |     100 |
| 12 |     120 |
+----+---------+
# 11那條資料回滾了,但是id也被消耗了,id不會回滾,

面試官:雖然AUTO-INC Locking可以不用等事務提交就釋放,但是在并發的時候,因為AUTO-INC Locking本身會對自增id上鎖的,還是會影響效率,這個該怎么解決?

我:現在InnoDB支持互斥量的方式來實作自增長,通過互斥量可以對記憶體中的計數器進行累加操作,比AUTO-INC Locking要快些,

面試官:那你知道死鎖嗎?

我:知道,

面試官:什么情況下會出現死鎖?

我:死鎖出現的條件就是請求和保持,就是每一方都保持著對方的需要的資源同時請求對方占用的資源,比如:

事務1先鎖id=1這條資料,緊接著事務2鎖住id=2這條資料,然后事務1再次嘗試鎖住id=2這條資料,但是發現被事務2占著在,所以此時事務1會阻塞,最后事務2嘗試獲取id=1的鎖,但是發現被事務1占著在,所以也會阻塞,那么此時就陷入僵局了,這就是死鎖,

面試官:那如何解決死鎖問題呢?

我:

  1. InnoDB提供鎖超時的功能,當一個事務獲取鎖超時之后會自動放棄,另一個事務就可以執行,
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50    |
+--------------------------+-------+
  1. 可以讓每次更新都按照約定的順序去更新,這樣也可以避免死鎖,

  1. 通過死鎖檢測來提前判斷,InnoDB默認是開啟死鎖檢測的,
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_deadlock_detect | ON    |
+------------------------+-------+

InnoDB通過等待圖的方式來進行死鎖檢測的,這要求存盤鎖的資訊鏈表和事務的等待鏈表,然后通過鏈表構造一張等待圖,每次獲取鎖的時候會通過等待圖來判斷是否會造成死鎖,

面試官看了看自己的勞力士:(看來今天鎖不住這個小伙子了,時間也差不多了)那你在這稍等下,我喊下hr,

我:好的好的(終于結束了),

微信搜【假裝懂編程】,一起深入交流

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/307364.html

標籤:其他

上一篇:利用國慶搭建了一個博客網站,一起來學習一下吧!

下一篇:ApplePTP-withCompleteContentCatalog沒有啟動(Rust Obj-C)。

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more