精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

面試官:為什么MySQL的行鎖有時(shí)會(huì)升級(jí)為表鎖?

數(shù)據(jù)庫(kù) MySQL
我們系統(tǒng)性地梳理了MySQL鎖機(jī)制的方方面面。從鎖與索引的共生關(guān)系,到不同維度下鎖的分類(行鎖與表鎖、共享鎖與排它鎖、意向鎖),再到InnoDB為了解決幻讀問(wèn)題而設(shè)計(jì)的三種核心鎖形態(tài)(記錄鎖、間隙鎖、臨鍵鎖),我們建立了一個(gè)相對(duì)完整的知識(shí)框架。

今天我們來(lái)深入探討一下MySQL中的鎖機(jī)制。在數(shù)據(jù)庫(kù)相關(guān)的面試中,鎖無(wú)疑是偏向高階且內(nèi)容較為零散的一類問(wèn)題。但它的重要性不言而喻,比如在實(shí)際工作中,一次突發(fā)的死鎖就可能嚴(yán)重影響線上服務(wù)的性能。這就要求我們作為后端工程師,必須對(duì)鎖有扎實(shí)的理解。并且,鎖的底層原理與索引、事務(wù)隔離級(jí)別息息相關(guān),這三個(gè)知識(shí)點(diǎn)常常在面試中被串聯(lián)起來(lái)提問(wèn),無(wú)論從哪個(gè)點(diǎn)切入,都很容易延伸到另外兩個(gè)。

因此,一句話總結(jié)鎖的特點(diǎn)就是:既是難點(diǎn),又是重點(diǎn),還是熱點(diǎn)。在這篇文章中,我將帶你徹底理清MySQL鎖的脈絡(luò),并告訴你如何在面試中將它轉(zhuǎn)化為你的核心亮點(diǎn)。

1. 鎖的核心知識(shí)回顧

1.1 鎖與索引的關(guān)系

在MySQL的InnoDB存儲(chǔ)引擎里,你必須牢記一個(gè)核心原則:鎖是借助索引來(lái)實(shí)現(xiàn)的。更具體地說(shuō),加鎖操作鎖住的并非數(shù)據(jù)行本身,而是數(shù)據(jù)行對(duì)應(yīng)的索引項(xiàng)。從B+樹(shù)的結(jié)構(gòu)來(lái)看,最終鎖定的就是葉子節(jié)點(diǎn)上的索引記錄。

1修復(fù)

只要你從這個(gè)視角出發(fā),就能理解絕大多數(shù)與鎖相關(guān)的、看似千奇百怪的問(wèn)題。

一個(gè)表可能存在多個(gè)索引,那么加鎖時(shí)究竟會(huì)鎖定哪個(gè)索引呢?答案是:查詢優(yōu)化器最終選擇使用的那個(gè)索引。那么,如果一條查詢語(yǔ)句因?yàn)闆](méi)有合適的索引而走了全表掃描呢?在這種情況下,InnoDB無(wú)法在索引上實(shí)現(xiàn)行級(jí)別的鎖定,只能退而求其次,將鎖的粒度從“行”上升到“表”,也就是我們常說(shuō)的表鎖

再來(lái)看一個(gè)有趣的場(chǎng)景:如果查詢條件所指定的值在數(shù)據(jù)庫(kù)中根本不存在,例如:

-- 嘗試鎖定一個(gè)不存在的記錄
SELECT * FROM your_tab WHERE id = 150 FOR UPDATE;

此時(shí)id=150這條記錄不存在,鎖會(huì)如何作用?InnoDB引擎會(huì)利用B+樹(shù)索引的有序性,找到與150相鄰的索引記錄(例如120和170),并在這兩條記錄之間構(gòu)建一個(gè)**臨鍵鎖 (Next-Key Lock)**,其鎖定的范圍是(120, 170]。

image-1

這個(gè)臨鍵鎖的作用就是防止其他事務(wù)向這個(gè)“間隙”中插入id=150的新記錄。

那么范圍查詢呢?其原理也是類似的。InnoDB會(huì)利用索引數(shù)據(jù),構(gòu)造一個(gè)剛好能覆蓋整個(gè)查詢范圍的臨鍵鎖。例如:

-- 對(duì)id大于330的記錄進(jìn)行范圍加鎖
SELECT * FROM your_tab WHERE id > 330 FOR UPDATE;

對(duì)于這條語(yǔ)句,InnoDB會(huì)構(gòu)建一個(gè)覆蓋范圍為(330, supremum]的臨鍵鎖。這里的supremum你可以直觀地理解為InnoDB內(nèi)部定義的一個(gè)虛擬的最大值,代表正無(wú)窮。

3修復(fù)

綜上所述,我們得出一個(gè)至關(guān)重要的結(jié)論:鎖與索引密不可分,鎖的粒度和效率直接取決于索引的使用情況

1.2 鎖的釋放時(shí)機(jī)

很多開(kāi)發(fā)者在學(xué)習(xí)鎖時(shí)會(huì)陷入一個(gè)誤區(qū),認(rèn)為鎖在SQL語(yǔ)句執(zhí)行完畢后就會(huì)立刻被釋放。這是一個(gè)錯(cuò)誤的觀念。實(shí)際上,InnoDB中的鎖是在整個(gè)事務(wù)結(jié)束時(shí)才會(huì)被釋放的。無(wú)論你是執(zhí)行COMMIT提交事務(wù),還是ROLLBACK回滾事務(wù),事務(wù)內(nèi)所有持有的鎖都會(huì)在那個(gè)時(shí)刻被統(tǒng)一釋放。

image

換言之,一個(gè)事務(wù)一旦給某份數(shù)據(jù)加上了鎖,這把鎖就會(huì)被一直持有,直到事務(wù)的終點(diǎn)。

1.3 樂(lè)觀鎖與悲觀鎖

樂(lè)觀鎖和悲觀鎖并非物理上真實(shí)存在的鎖,而是兩種并發(fā)控制的邏輯思想和設(shè)計(jì)哲學(xué)。

  • 悲觀鎖:它總是假設(shè)最壞的情況,認(rèn)為數(shù)據(jù)在任何時(shí)候都可能被其他事務(wù)修改。因此,在操作數(shù)據(jù)之前,它會(huì)先將數(shù)據(jù)鎖定,以阻止任何可能的并發(fā)修改。SELECT ... FOR UPDATE就是悲觀鎖最典型的實(shí)現(xiàn)。
  • 樂(lè)觀鎖:它則持有非常“樂(lè)觀”的態(tài)度,假設(shè)在自己操作數(shù)據(jù)的這段時(shí)間里,別人不會(huì)來(lái)修改它。因此,它在操作數(shù)據(jù)時(shí)不會(huì)加鎖,而是在最后提交更新的時(shí)候,去檢查一下數(shù)據(jù)是否被修改過(guò)。

在數(shù)據(jù)庫(kù)中,樂(lè)觀鎖通常指利用類似CAS(Compare-And-Swap,比較并交換)的思路去更新數(shù)據(jù)。其一般的使用形態(tài)如下:

-- 1. 先查詢出數(shù)據(jù),獲取當(dāng)前值(比如 a=1)
SELECT * FROM your_tab WHERE id=1; 

-- ... 在應(yīng)用層執(zhí)行一系列復(fù)雜的業(yè)務(wù)邏輯 ...

-- 2. 更新時(shí),將之前查詢到的值作為WHERE條件的一部分
UPDATE your_tab SET a=3, b=4 WHERE id=1 AND a=1;

在上述UPDATE語(yǔ)句中,我們預(yù)期數(shù)據(jù)庫(kù)中a的值仍然是我們最初讀到的1。如果在我們進(jìn)行業(yè)務(wù)操作期間,a的值被其他事務(wù)修改了,那么這條UPDATE語(yǔ)句的WHERE條件將不成立,更新操作就會(huì)失敗(影響行數(shù)為0)。業(yè)務(wù)方通過(guò)判斷受影響的行數(shù),就能得知此次并發(fā)更新是否成功。

5修復(fù)

而悲觀鎖的實(shí)現(xiàn)則更為直接,它從一開(kāi)始就鎖定了資源:

-- 1. 在查詢時(shí)就直接加上排它鎖
SELECT * FROM your_tab WHERE id=1 FOR UPDATE;

-- ... 在應(yīng)用層執(zhí)行一系列復(fù)雜的業(yè)務(wù)邏輯 ...

-- 2. 直接更新數(shù)據(jù),因?yàn)閿?shù)據(jù)已被鎖定,無(wú)需擔(dān)心被修改
UPDATE your_tab SET a=3, b=4 WHERE id=1;

在選擇這兩種鎖時(shí),需要權(quán)衡數(shù)據(jù)一致性與并發(fā)性能。樂(lè)觀鎖更適用于讀多寫少的場(chǎng)景,這也是絕大多數(shù)互聯(lián)網(wǎng)應(yīng)用的特征,它的性能開(kāi)銷更小。而悲觀鎖則適用于寫多讀少或?qū)?shù)據(jù)一致性要求極高的場(chǎng)景,例如金融領(lǐng)域?qū)~戶金額的操作,通常以寫操作為主。

相比之下,樂(lè)觀鎖能提供更好的并發(fā)性能。不過(guò),由于其實(shí)現(xiàn)邏輯需要應(yīng)用層配合,寫起來(lái)相對(duì)復(fù)雜,所以很多開(kāi)發(fā)者為了圖省事,會(huì)傾向于直接使用悲觀鎖。

1.4 行鎖與表鎖

行鎖與表鎖是根據(jù)鎖定的范圍(粒度)來(lái)劃分的。顧名思義,行鎖鎖住的是數(shù)據(jù)行,可能是一行,也可能是多行。而表鎖則直接將整張數(shù)據(jù)表鎖定。

在MySQL中,InnoDB存儲(chǔ)引擎同時(shí)支持行鎖和表鎖。但必須再次強(qiáng)調(diào),行鎖的實(shí)現(xiàn)強(qiáng)依賴于索引。如果你的查詢無(wú)法命中任何索引,導(dǎo)致全表掃描,那么InnoDB將無(wú)法使用行鎖,只能退而求其次,使用表鎖。當(dāng)然,如果你使用的是一些較老的存儲(chǔ)引擎,如MyISAM,那么它從設(shè)計(jì)上就只支持表鎖。

1.5 共享鎖與排它鎖

共享鎖和排它鎖是從互斥性的角度來(lái)看待鎖的。

  • 共享鎖 (Shared Lock, S鎖):也稱讀鎖。一個(gè)事務(wù)對(duì)某行數(shù)據(jù)加上S鎖后,其他事務(wù)仍然可以繼續(xù)對(duì)該行加S鎖,但不能加排它鎖(X鎖)。它允許多個(gè)事務(wù)同時(shí)讀取同一份數(shù)據(jù)。
  • 排它鎖 (Exclusive Lock, X鎖):也稱寫鎖。一個(gè)事務(wù)對(duì)某行數(shù)據(jù)加上X鎖后,其他任何事務(wù)都不能再對(duì)該行加任何類型的鎖(無(wú)論是S鎖還是X鎖),直到持有鎖的事務(wù)釋放。它保證了在任何時(shí)刻,只有一個(gè)事務(wù)能修改數(shù)據(jù)。

它們的兼容關(guān)系如下表所示:

類型

共享鎖

排它鎖

共享鎖

兼容

不兼容

排它鎖

不兼容

不兼容

1.6 意向鎖

意向鎖是一種表級(jí)鎖,但它本身并不真正鎖定數(shù)據(jù),更像是一個(gè)“信號(hào)”或“標(biāo)志”。它的核心作用是告訴其他事務(wù):“我(某個(gè)事務(wù))正準(zhǔn)備或已經(jīng)對(duì)這個(gè)表里的某些行加鎖了”。

意向鎖與共享鎖、排它鎖結(jié)合,就產(chǎn)生了兩種意向鎖:

  • 意向共享鎖 (Intention Shared Lock, IS鎖):表示一個(gè)事務(wù)希望獲得表中某些行的共享鎖。
  • 意向排它鎖 (Intention Exclusive Lock, IX鎖):表示一個(gè)事務(wù)希望獲得表中某些行的排它鎖。

注意,“意向”強(qiáng)調(diào)的是一種打算,但最終能否成功獲得行鎖是不確定的。

在MySQL中,使用意向鎖的典型場(chǎng)景是協(xié)調(diào)行鎖和表鎖的關(guān)系。當(dāng)一個(gè)事務(wù)需要對(duì)表中的行加S鎖或X鎖時(shí),它會(huì)先在表級(jí)別加上IS鎖或IX鎖。之后,如果另一個(gè)事務(wù)想要獲取整個(gè)表的表鎖(例如LOCK TABLES ... WRITE),它就無(wú)需逐行檢查是否有行鎖存在,只需檢查表級(jí)別是否存在意向鎖即可。這極大地提高了數(shù)據(jù)庫(kù)的并發(fā)性能,并避免了不必要的死鎖。這也是為什么在修改表結(jié)構(gòu)(DDL)時(shí),會(huì)阻塞所有增刪改查(DML)語(yǔ)句的原因。

1.7 記錄鎖、間隙鎖和臨鍵鎖:深度剖析

這是面試中最能檢驗(yàn)候選人技術(shù)深度的部分,也是最容易混淆的概念。反過(guò)來(lái)說(shuō),如果你能將這部分的細(xì)節(jié)闡述清晰,本身就是一個(gè)非常大的亮點(diǎn)。

1.7.1 記錄鎖 (Record Lock)

記錄鎖非常直觀,它鎖定的是某一條特定的索引記錄。通常,當(dāng)你的查詢條件是等值查詢,并且精準(zhǔn)地命中了主鍵唯一索引時(shí),InnoDB就會(huì)使用記錄鎖。

-- 假設(shè)id是主鍵,這條語(yǔ)句會(huì)對(duì)id=310這一條記錄加上記錄鎖
SELECT * FROM your_tab WHERE id = 310 FOR UPDATE;

6修復(fù)

如果查詢條件作用在唯一索引上,且能命中一條記錄,效果是完全一樣的。假設(shè)email字段有唯一索引,這條語(yǔ)句也會(huì)使用記錄鎖

-- 假設(shè)email字段有唯一索引,這條語(yǔ)句也會(huì)使用記錄鎖
SELECT * FROM your_tab WHERE email='your_email' FOR UPDATE;

但是,如果等值查詢沒(méi)有命中任何記錄,那么就不會(huì)使用記錄鎖,而是會(huì)使用間隙鎖。比如數(shù)據(jù)庫(kù)中只有 id 為(10,40,70)的三條記錄,也就是 id= 30 這個(gè)條件沒(méi)有命中任何數(shù)據(jù),那么這條語(yǔ)句會(huì)在(10,40)加上間隙鎖,注意,這里是對(duì)一個(gè)左開(kāi)右開(kāi)的區(qū)間加鎖。可以看到, 即便是是對(duì)字段加了唯一索引,但是如果查詢沒(méi)有命中索引,對(duì)性能影響也是很大的。

1.7.2 間隙鎖 (Gap Lock)

間隙鎖鎖定的是一個(gè)開(kāi)區(qū)間范圍,即兩條索引記錄之間的“空隙”,但它不包括記錄本身。它的主要作用是在可重復(fù)讀隔離級(jí)別下,防止其他事務(wù)在這個(gè)“間隙”中插入新的記錄,從而避免“幻讀”問(wèn)題。通常,范圍查詢(如<<=BETWEEN)會(huì)使用到間隙鎖。

-- 這條語(yǔ)句會(huì)鎖住(500, 1000)這個(gè)開(kāi)區(qū)間
SELECT * FROM your_tab WHERE id BETWEEN 500 AND 1000 FOR UPDATE;

間隙鎖會(huì)鎖住(500, 1000)之間的數(shù)據(jù),而500和1000這兩條記錄本身則會(huì)被記錄鎖鎖住。如果你的表中沒(méi)有id=500的記錄,數(shù)據(jù)庫(kù)會(huì)一直向左找到第一個(gè)存在的數(shù)據(jù)(比如400);如果沒(méi)有id=100的記錄,則會(huì)一直向右找到第一個(gè)存在的數(shù)據(jù)(比如1200)。那么此時(shí)使用的間隙鎖范圍就是(400, 1200)。在這種情況下,如果有人想插入一條主鍵為700的行,操作就會(huì)被阻塞。

一個(gè)非常重要的特性是:間隙鎖和間隙鎖之間是不排它的。也就是說(shuō),兩個(gè)不同的事務(wù),即使它們申請(qǐng)的間隙鎖范圍有重疊,也可以同時(shí)加鎖成功。

7修復(fù)

1.7.3 臨鍵鎖 (Next-Key Lock)

臨鍵鎖是InnoDB在可重復(fù)讀隔離級(jí)別下默認(rèn)的鎖定算法。從直觀上,你可以把它看作是一個(gè)記錄鎖和一個(gè)間隙鎖的組合。也就是說(shuō),臨鍵鎖不僅會(huì)用記錄鎖鎖住命中的記錄,還會(huì)用間隙鎖鎖住該記錄之前的那個(gè)空隙。臨鍵鎖的鎖定區(qū)間是一個(gè)左開(kāi)右閉的區(qū)間。

還是用前面的例子,如果索引中只有(10, 40, 70)三條記錄,那么一個(gè)臨鍵鎖就可以將(10, 40]這個(gè)區(qū)間鎖住。臨鍵鎖與數(shù)據(jù)庫(kù)的隔離級(jí)別聯(lián)系最為緊密,它正是解決幻讀問(wèn)題的關(guān)鍵所在。

1.7.4 加鎖規(guī)則總結(jié)

為了更清晰地理解這三種鎖的適用場(chǎng)景,我們可以將其總結(jié)為一套判斷法則。這套法則的核心在于理解臨鍵鎖作為默認(rèn)行為,以及它在特定條件下的“退化”現(xiàn)象。

  • 基礎(chǔ)原則:默認(rèn)使用臨鍵鎖 在可重復(fù)讀(RR)隔離級(jí)別下,臨鍵鎖是InnoDB的基石和默認(rèn)選擇。無(wú)論是等值查詢還是范圍查詢,InnoDB首先傾向于使用臨鍵鎖來(lái)鎖定相關(guān)記錄及其前方的間隙,以此來(lái)杜絕幻讀的可能。
  • 優(yōu)化特例:退化為記錄鎖 當(dāng)查詢能夠?qū)崿F(xiàn)最精準(zhǔn)的定位時(shí),臨鍵鎖會(huì)進(jìn)行優(yōu)化,退化為粒度更細(xì)的記錄鎖。這個(gè)特例的觸發(fā)條件非常嚴(yán)格:

a.查詢條件必須是等值查詢(如 id = ? 或 email = ?)。

b.查詢的列必須是主鍵唯一索引

c.查詢結(jié)果必須精確命中一條存在的記錄。 只有同時(shí)滿足這三個(gè)條件,InnoDB才會(huì)放棄對(duì)間隙的鎖定,只對(duì)該條記錄加記錄鎖。

  • 另一特例:退化為間隙鎖 在某些情況下,臨鍵鎖中“鎖定記錄”的部分會(huì)消失,使其退化為純粹的間隙鎖。這通常發(fā)生在:

a.查詢的范圍不包含任何存在的記錄,例如 WHERE id > 100(假設(shè)100是最大ID)。

b.查詢一個(gè)在索引中不存在的值,例如 WHERE id = 15(假設(shè)12和17是相鄰記錄)。 在這些場(chǎng)景下,由于沒(méi)有具體的“記錄”可鎖,鎖定的重點(diǎn)就完全落在了防止新數(shù)據(jù)插入的“間隙”上。

8修復(fù)

需要注意的是,對(duì)于普通索引,即使是等值查詢,因?yàn)樗饕悼赡苤貜?fù),InnoDB為了防止幻讀,仍然會(huì)使用臨鍵鎖,而不是退化為記錄鎖。

2. 面試實(shí)戰(zhàn)指南

2.1 面試案例準(zhǔn)備

要在面試中脫穎而出,僅有理論知識(shí)是遠(yuǎn)遠(yuǎn)不夠的。面試官更看重你解決實(shí)際問(wèn)題的能力。因此,你需要主動(dòng)構(gòu)建一個(gè)屬于自己的實(shí)戰(zhàn)案例庫(kù)。

  • 復(fù)盤線上問(wèn)題:主動(dòng)去了解和復(fù)盤公司發(fā)生過(guò)的與鎖相關(guān)的線上故障,特別是那些導(dǎo)致服務(wù)抖動(dòng)或中斷的死鎖案例。你需要搞清楚問(wèn)題的全貌:它是在什么業(yè)務(wù)場(chǎng)景下觸發(fā)的?排查過(guò)程是怎樣的?最終是如何解決的?有沒(méi)有留下什么隱患?
  • 挖掘性能瓶頸:審視你負(fù)責(zé)的業(yè)務(wù),思考是否存在因?yàn)殒i使用不當(dāng)而導(dǎo)致的性能問(wèn)題。比如,某個(gè)核心接口的響應(yīng)時(shí)間(RT)很高,有沒(méi)有可能是因?yàn)槟硞€(gè)事務(wù)持有了過(guò)大的鎖(如表鎖)或者鎖的持有時(shí)間過(guò)長(zhǎng)?
  • 解構(gòu)鎖的應(yīng)用模式:在公司的代碼庫(kù)中,主動(dòng)去尋找和分析樂(lè)觀鎖與悲觀鎖的實(shí)際應(yīng)用。對(duì)于樂(lè)觀鎖,它的CAS操作具體是如何通過(guò)SQL實(shí)現(xiàn)的?版本號(hào)是如何管理的?對(duì)于悲觀鎖,SELECT ... FOR UPDATE用在哪些關(guān)鍵業(yè)務(wù)上?這些用法是否合理?有沒(méi)有優(yōu)化的空間?

通過(guò)這種方式,將別人的經(jīng)驗(yàn)和線上的教訓(xùn)內(nèi)化為自己的知識(shí),你才能在面試中言之有物。同時(shí),你需要刻意訓(xùn)練自己分析SQL加鎖行為的能力,拿到一條SQL和表結(jié)構(gòu),就能大致推斷出它在特定隔離級(jí)別下會(huì)加什么鎖,影響范圍有多大,這會(huì)讓你顯得非常專業(yè)。

2.2 面試應(yīng)答技巧

當(dāng)面試官拋出“談?wù)勀銓?duì)MySQL鎖的理解”這類宏觀問(wèn)題時(shí),你的回答需要有層次感,先搭建框架,再填充細(xì)節(jié)。

你可以這樣開(kāi)場(chǎng),先給出一個(gè)全局視圖:

“好的。對(duì)于MySQL的鎖,我習(xí)慣從幾個(gè)不同的維度去理解它。首先,從鎖定粒度上,有我們熟知的行鎖表鎖。其次,從鎖的兼容性上,可以分為共享鎖(S鎖)和排它鎖(X鎖),這決定了它們是否可以共存。

在這兩個(gè)基礎(chǔ)維度之上,InnoDB為了提升性能,還引入了意向鎖,它是一種表級(jí)鎖,用來(lái)預(yù)示事務(wù)接下來(lái)想要加的行鎖類型。

而在InnoDB的行鎖實(shí)現(xiàn)中,又有三種具體的鎖算法,這也是面試中的重點(diǎn):記錄鎖間隙鎖臨鍵鎖。它們是InnoDB在RR級(jí)別下解決幻讀問(wèn)題的核心。

最后,從編程思想的層面,我們還有樂(lè)觀鎖悲觀鎖的概念,它們是我們?cè)趹?yīng)用層進(jìn)行并發(fā)控制的兩種不同策略。”

在構(gòu)建了整體認(rèn)知框架后,再拋出鎖機(jī)制的兩個(gè)核心支柱:

“要深入理解InnoDB的鎖,關(guān)鍵在于抓住兩個(gè)核心:索引事務(wù)隔離級(jí)別。InnoDB的行鎖是構(gòu)建在索引之上的,沒(méi)有索引,行鎖就無(wú)從談起,只能退化為表鎖。而像臨鍵鎖和間隙鎖這類精細(xì)的鎖定策略,其主要舞臺(tái)是在可重復(fù)讀(RR)這個(gè)隔離級(jí)別下,其根本目的是為了解決幻讀問(wèn)題。”

這樣的回答方式,先展現(xiàn)了你知識(shí)的廣度和體系性,然后點(diǎn)出了問(wèn)題的本質(zhì),自然會(huì)引導(dǎo)面試官對(duì)你感興趣的深層部分進(jìn)行追問(wèn),比如:

  • “你剛才提到的臨鍵鎖,能詳細(xì)講講它的工作原理和使用場(chǎng)景嗎?”
  • “既然RR級(jí)別有臨鍵鎖可以防止幻讀,那它在什么極端情況下還會(huì)出現(xiàn)幻讀呢?”
  • “你在項(xiàng)目中是如何選擇使用樂(lè)觀鎖還是悲觀鎖的?能舉個(gè)例子嗎?”
  • “聽(tīng)起來(lái)你對(duì)鎖研究得比較深,有沒(méi)有處理過(guò)線上死鎖問(wèn)題的經(jīng)驗(yàn)?”

當(dāng)面試官開(kāi)始追問(wèn)這些細(xì)節(jié)時(shí),你就成功地將面試的主動(dòng)權(quán)掌握在了自己手中,接下來(lái)就是你展示項(xiàng)目經(jīng)驗(yàn)和技術(shù)深度的最佳時(shí)機(jī)。

2.3 面試亮點(diǎn)方案

2.3.1 基礎(chǔ)優(yōu)化:為高頻查詢添加索引

這是一個(gè)基礎(chǔ)卻非常有效的優(yōu)化,你可以把它作為一個(gè)“排查線上性能抖動(dòng)”的故事來(lái)講述。

“我曾經(jīng)處理過(guò)一個(gè)線上問(wèn)題,某個(gè)核心服務(wù)的性能會(huì)周期性地出現(xiàn)毛刺,響應(yīng)時(shí)間突然飆升。經(jīng)過(guò)一系列排查,我們定位到瓶頸在于數(shù)據(jù)庫(kù)。但奇怪的是,通過(guò)慢查詢?nèi)罩咀サ降腟QL,單獨(dú)執(zhí)行時(shí)速度很快,并且EXPLAIN分析也顯示它命中了索引。


后來(lái),我們通過(guò)SHOW PROCESSLIST和數(shù)據(jù)庫(kù)監(jiān)控,才發(fā)現(xiàn)在性能抖動(dòng)的時(shí)刻,有大量正常的查詢都阻塞在Waiting for table metadata lock狀態(tài)。我們順藤摸瓜,最終發(fā)現(xiàn)源頭是后臺(tái)一個(gè)新功能引入的報(bào)表SQL。這條SQL的查詢條件非常復(fù)雜,且沒(méi)有建立合適的索引,導(dǎo)致它在執(zhí)行時(shí),MySQL對(duì)目標(biāo)表施加了表鎖。由于報(bào)表查詢數(shù)據(jù)量大,執(zhí)行時(shí)間長(zhǎng),這個(gè)表鎖被長(zhǎng)時(shí)間持有,從而阻塞了所有其他針對(duì)該表的正常業(yè)務(wù)操作。


找到問(wèn)題后,解決方案就很明確了:我們與業(yè)務(wù)方溝通,優(yōu)化了這條SQL,并為其添加了合適的復(fù)合索引,使其從表鎖降級(jí)為行鎖。上線后,服務(wù)性能毛刺的問(wèn)題就徹底消失了。”

2.3.2 進(jìn)階方案:破解臨鍵鎖引發(fā)的并發(fā)死鎖

這個(gè)案例更能體現(xiàn)你對(duì)InnoDB鎖機(jī)制的深度理解。

“我們有一個(gè)業(yè)務(wù)場(chǎng)景,需要在一個(gè)事務(wù)里先查詢某個(gè)資源位是否存在,如果不存在,就計(jì)算并插入一個(gè)新資源;如果已存在,就基于現(xiàn)有資源進(jìn)行更新。這個(gè)邏輯可以簡(jiǎn)化為‘查詢并鎖定,然后插入或更新’。

9修復(fù)

偽代碼大概是這樣:

BEGIN;
SELECT * FROM resource WHERE position = ? FOR UPDATE;
-- 如果記錄不存在
INSERT INTO resource (...) VALUES (...);
-- 如果記錄存在
-- UPDATE resource SET ... WHERE position = ?;
COMMIT;

看起來(lái)是不是沒(méi)有任何問(wèn)題?實(shí)際上,這個(gè)地方在高并發(fā)下會(huì)引起死鎖。

假設(shè)現(xiàn)在數(shù)據(jù)庫(kù)中ID最大的值是780。那么如果兩個(gè)業(yè)務(wù)線程幾乎同時(shí)進(jìn)來(lái),執(zhí)行這段邏輯,一個(gè)準(zhǔn)備插入id=790的數(shù)據(jù),一個(gè)準(zhǔn)備插入id=800的數(shù)據(jù)。如果它們的執(zhí)行時(shí)序如下圖所示,那么你就會(huì)得到一個(gè)死鎖錯(cuò)誤。

10修復(fù)


這段代碼在并發(fā)量上來(lái)后,頻繁地引發(fā)數(shù)據(jù)庫(kù)死鎖。經(jīng)過(guò)復(fù)盤,我們發(fā)現(xiàn)死鎖的根源在于臨鍵鎖。假設(shè)position索引當(dāng)前的最大值是780,兩個(gè)并發(fā)事務(wù)分別嘗試操作positinotallow=790positinotallow=800。由于這兩條記錄都不存在,它們都會(huì)在(780, +∞)這個(gè)間隙上成功獲得臨鍵鎖。接著,事務(wù)A想插入790,需要獲取790的行鎖,但這個(gè)位置被事務(wù)B的臨鍵鎖覆蓋,于是等待;同時(shí),事務(wù)B想插入800,也被事務(wù)A的臨鍵鎖覆蓋,也開(kāi)始等待。這樣,兩個(gè)事務(wù)互相等待對(duì)方釋放自己需要的間隙,就形成了死鎖。

11修復(fù)

針對(duì)這個(gè)問(wèn)題,我們當(dāng)時(shí)探討了三種解決方案:

  1. 調(diào)整業(yè)務(wù)邏輯:將‘先查后插’改為‘直接插入’。我們嘗試直接INSERT,如果成功,說(shuō)明資源位原先為空;如果因?yàn)橹麈I或唯一鍵沖突而失敗,則說(shuō)明資源位已存在,再去執(zhí)行更新邏輯。這樣,成功的事務(wù)從一開(kāi)始就持有行鎖,而不是臨鍵鎖,從而規(guī)避了死鎖。
  2. 降低隔離級(jí)別:將事務(wù)的隔離級(jí)別從RR降為RC(讀已提交)。在RC級(jí)別下,沒(méi)有間隙鎖,自然也就沒(méi)有臨鍵鎖,死鎖問(wèn)題迎刃而解。但這個(gè)方案影響較大,需要評(píng)估業(yè)務(wù)是否能接受RC級(jí)別可能帶來(lái)的不可重復(fù)讀和幻讀問(wèn)題。
  3. 改用樂(lè)觀鎖:完全放棄悲觀鎖,但這需要對(duì)代碼進(jìn)行較大范圍的重構(gòu)。

最終,我們選擇了第一種方案,因?yàn)樗鼘?duì)代碼的侵入性最小,且效果立竿見(jiàn)影。”

2.3.3 終極方案:以樂(lè)觀鎖替代不必要的悲觀鎖

你可以將這個(gè)案例包裝成一次主動(dòng)的技術(shù)重構(gòu),體現(xiàn)你的架構(gòu)思維和性能意識(shí)。

“在我之前負(fù)責(zé)的一個(gè)項(xiàng)目中,我注意到許多核心業(yè)務(wù)模塊為了保證數(shù)據(jù)一致性,普遍采用了SELECT ... FOR UPDATE的悲觀鎖模式。這種模式雖然簡(jiǎn)單可靠,但在讀多寫少的場(chǎng)景下,會(huì)造成不必要的線程等待,極大地限制了系統(tǒng)的并發(fā)能力。

因此,我主導(dǎo)了一項(xiàng)技術(shù)優(yōu)化,對(duì)這些不必要的悲觀鎖進(jìn)行樂(lè)觀鎖改造。改造的核心思想是,在事務(wù)中去掉FOR UPDATE,并在UPDATE語(yǔ)句中增加對(duì)數(shù)據(jù)版本的校驗(yàn)。

改造前的偽代碼:

// 開(kāi)啟事務(wù)并加鎖
tx.Begin()
data := tx.SelectForUpdate(id) 
// 業(yè)務(wù)計(jì)算
newData := calculate(data)
tx.Update(newData)
tx.Commit()

改造后的偽代碼:

for {
    // 1. 普通查詢,獲取數(shù)據(jù)和版本號(hào)
    data, version := SelectWithVersion(id)
    // 2. 業(yè)務(wù)計(jì)算
    newData := calculate(data)
    // 3. CAS更新,通過(guò)版本號(hào)防止并發(fā)修改
    rowsAffected := UpdateWithCAS(id, newData, version)
    // 4. 如果更新成功(影響行數(shù)為1),則退出循環(huán)
    if rowsAffected == 1 {
        break
    }
    // 如果更新失敗,則循環(huán)重試
}

這次重構(gòu)的效果非常顯著,核心接口的吞吐量提升了將近30%。當(dāng)然,這個(gè)方案并非萬(wàn)能靈藥。對(duì)于那些寫沖突非常頻繁的業(yè)務(wù),使用樂(lè)觀鎖可能會(huì)導(dǎo)致大量的重試,反而降低性能,這種場(chǎng)景下保留悲觀鎖依然是更明智的選擇。”

3. 小結(jié)

這篇文章,我們系統(tǒng)性地梳理了MySQL鎖機(jī)制的方方面面。從鎖與索引的共生關(guān)系,到不同維度下鎖的分類(行鎖與表鎖、共享鎖與排它鎖、意向鎖),再到InnoDB為了解決幻讀問(wèn)題而設(shè)計(jì)的三種核心鎖形態(tài)(記錄鎖、間隙鎖、臨鍵鎖),我們建立了一個(gè)相對(duì)完整的知識(shí)框架。

更重要的是,我們必須認(rèn)識(shí)到,對(duì)鎖的理解不能止步于理論。無(wú)論是通過(guò)“為缺失索引的查詢補(bǔ)上索引”來(lái)避免表鎖的基礎(chǔ)優(yōu)化,還是分析“臨鍵鎖引發(fā)死鎖”和“以樂(lè)觀鎖替代悲觀鎖”這類更復(fù)雜的實(shí)戰(zhàn)場(chǎng)景,最終目的都是為了將理論知識(shí)轉(zhuǎn)化為解決實(shí)際問(wèn)題的能力。你在面試中準(zhǔn)備的案例,不應(yīng)僅僅是背誦的腳本,而應(yīng)是你對(duì)這些問(wèn)題深入思考和理解的體現(xiàn)。

責(zé)任編輯:武曉燕 來(lái)源: IT楊秀才
相關(guān)推薦

2022-11-08 17:39:27

MySQLkilled

2025-08-04 00:00:00

樂(lè)觀讀鎖并發(fā)編程共享讀鎖

2025-10-31 02:00:00

2024-01-11 08:12:20

重量級(jí)監(jiān)視器

2025-11-10 03:00:00

2021-12-16 18:38:13

面試Synchronize

2020-09-16 07:56:28

多線程讀寫鎖悲觀鎖

2024-08-12 17:36:54

2023-02-08 08:32:41

輪詢鎖

2024-11-29 07:38:12

MySQL數(shù)據(jù)庫(kù)

2023-06-30 07:58:07

Spring數(shù)據(jù)源事務(wù)

2025-02-10 09:58:48

2022-12-27 08:39:54

MySQL主鍵索引

2024-06-03 00:00:01

索引MySQL技術(shù)

2025-08-04 08:05:28

2022-07-04 08:06:14

Go語(yǔ)言互斥鎖

2018-07-31 10:10:06

MySQLInnoDB死鎖

2021-02-19 10:02:57

HTTPSJava安全

2020-10-20 13:50:47

MySQL數(shù)據(jù)庫(kù)

2010-05-24 12:50:59

MySQL表級(jí)鎖
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

性久久久久久久久| 台湾佬综合网| 亚洲精品一二三| 亚洲中国色老太| 国产成人无码精品久久久久| 最新国产一区| 欧美一级欧美三级| 国产精品视频一区二区三区四区五区| yjizz视频网站在线播放| 久久成人精品无人区| 欧美激情三级免费| 国产精品露脸自拍| 欧美福利精品| 国产精品久久久久精| 精久久久久久| 色噜噜国产精品视频一区二区| 欧美一级大片免费看| 神马久久资源| 亚洲高清免费在线| 宅男一区二区三区| 精品视频二区| 成人免费三级在线| 91精品视频免费| 最新中文字幕一区| 欧美+日本+国产+在线a∨观看| 亚洲天堂精品在线| 国产xxxxxxxxx| 国产精品99久久免费| 91久久国产综合久久| 大伊香蕉精品视频在线| 黄色网页在线免费看| 国产色一区二区| 黑人巨大精品欧美一区二区小视频 | 欧美日韩尤物久久| 精品久久久国产| 中国丰满熟妇xxxx性| 成人av免费| 中文字幕在线播放不卡一区| 欧美三级电影在线播放| 日产精品久久久久久久性色| 成人v精品蜜桃久久一区| 97免费资源站| 精品国产无码AV| 精品制服美女久久| 国产在线98福利播放视频| 91在线视频免费播放| 国产精品久久久久久久久久妞妞| 欧美激情国内偷拍| 激情五月婷婷在线| 欧美日韩1区| 欧美二区在线播放| 久久久全国免费视频| 狠狠88综合久久久久综合网| 欧美精品免费在线| 国产成人精品视频在线| 国产精品欧美性爱| 日韩欧美久久| 欧美va日韩va| 国产一级黄色录像| 最近国产精品视频| 在线成人免费网站| 国产传媒免费在线观看| 自拍视频亚洲| 久久久久久久久久久亚洲| 精品人妻在线播放| 国产精品亚洲综合久久| 日本乱人伦a精品| 中文字幕乱伦视频| 久久福利资源站| 亚洲淫片在线视频| 日韩一区二区三区不卡| av男人天堂一区| 欧美午夜精品久久久久免费视| 国产在线视频你懂得| 国产精品久久免费看| 黄色录像特级片| 俄罗斯一级**毛片在线播放| 欧美日韩中文字幕在线| 色播五月综合网| 免费看日产一区二区三区| 日韩免费视频一区| 女尊高h男高潮呻吟| 精品一区二区三区中文字幕老牛| 日韩综合视频在线观看| 久久免费黄色网址| 日日夜夜免费精品| 亚洲aⅴ日韩av电影在线观看 | 电影亚洲精品噜噜在线观看| 欧美日韩午夜在线| 蜜桃视频无码区在线观看| 欧美人与动xxxxz0oz| 国产一区av在线| 福利所第一导航| 国产精品一页| 91丝袜美腿美女视频网站| 欧日韩在线视频| 中文字幕的久久| 国产日本在线播放| 欧美啪啪网站| 亚洲国产日韩欧美综合久久| 欧美久久精品一级黑人c片| 天堂久久久久久| 欧美oldwomenvideos| 久久久最新网址| 亚洲影院一区二区三区| 99在线精品观看| 在线观看欧美一区| 黄色综合网址| 亚洲国产91精品在线观看| 国产精品1区2区3区4区| 国产日韩视频| 亚洲综合在线播放| 波多野结衣在线网站| 亚洲h精品动漫在线观看| 欧美美女一级片| 综合伊人久久| 亚洲香蕉伊综合在人在线视看| 国产中文字幕免费| 国产精品综合视频| 亚洲精品一区二区毛豆| www.成人影院| 日韩av最新在线观看| 全程偷拍露脸中年夫妇| 麻豆国产一区二区| 欧美性色黄大片人与善| 黄色视屏在线免费观看| 欧美r级电影在线观看| 亚洲综合网在线| 蜜臀av性久久久久蜜臀aⅴ四虎| 乱一区二区三区在线播放| sis001亚洲原创区| 精品国产91洋老外米糕| 青青草手机视频在线观看| 国内外成人在线| 一区二区精品国产| 欧美亚洲二区| 自拍偷拍亚洲区| 中文字幕免费观看视频| 国产欧美日韩亚州综合 | 日本中文在线一区| 欧美日韩成人一区二区三区| 中文字幕高清在线播放| 日韩精品在线播放| 视频一区二区三区四区五区| 99久久国产综合色|国产精品| 日韩精品视频在线观看视频| 波多野结衣在线一区二区| 九九热99久久久国产盗摄| 99热这里只有精品1| 国产aⅴ精品一区二区三区久久| 亚洲黄色av一区| www.国产福利| 亚洲电影影音先锋| 99久久国产免费免费| 1区2区3区在线视频| 欧美一区三区二区| 久久久久久久极品内射| 成人免费av网站| 阿v天堂2017| 日韩母乳在线| 国产精品久久婷婷六月丁香| 亚洲欧美视频一区二区| 欧美精品亚洲一区二区在线播放| 国产中文av在线| 国产精品一区二区男女羞羞无遮挡| 少妇一晚三次一区二区三区| 精品精品国产三级a∨在线| 青青久久aⅴ北条麻妃| 国产私人尤物无码不卡| 欧美精品777| 久久久国产精华液| 久久综合色综合88| 91极品视频在线观看| 中文字幕一区二区av| 日韩暖暖在线视频| 日韩一卡二卡在线观看| 国产一区二区看久久| 国产在线视频在线| 欧美综合精品| 国产精品久久久久久久电影| 黄网页在线观看| 亚洲国产精品大全| 国产午夜无码视频在线观看 | 国产三区精品| 日韩一区二区三区免费| 麻豆成人在线看| 天堂网www中文在线| 欧美亚洲国产一卡| 在线观看成人毛片| 久久久久国产一区二区三区四区| 中文字幕成人在线视频| 日韩午夜激情| 亚洲欧美国产一区二区| 盗摄牛牛av影视一区二区| 国产精品久久久久久久app| 牛牛精品在线视频| 伊人伊成久久人综合网站| 亚洲精品喷潮一区二区三区| 婷婷综合网站| 亚洲欧美一区二区三区情侣bbw | 女人18毛片毛片毛片毛片区二| 国产不卡高清在线观看视频| 老司机午夜av| 日韩视频一区| 看全色黄大色大片| 成人短片线上看| 国语精品免费视频| 麻豆久久一区| 国产精品视频资源| 亚洲小少妇裸体bbw| 欧美日韩第一页| 91精彩在线视频| 日韩电影免费观看中文字幕| 国产黄色一区二区| 欧美日韩大陆一区二区| 一级成人黄色片| 亚洲国产美国国产综合一区二区| 欧美性生交大片| 久久久久国产成人精品亚洲午夜| 久久黄色一级视频| 韩国欧美国产1区| 中文字幕第21页| 媚黑女一区二区| 成熟丰满熟妇高潮xxxxx视频| 欧美va亚洲va日韩∨a综合色| 亚洲精品日韩在线观看| 波多野结衣在线观看一区二区三区 | 久久久久久久久久久免费精品 | 曰本一区二区三区视频| 不卡视频一区| 日本免费精品| 成人字幕网zmw| 欧美亚洲黄色| 91精品久久久久久久久久久久久久 | 日韩高清国产一区在线| 男女视频网站在线观看| 国色天香一区二区| 99热这里只有精品免费| 91精品精品| eeuss中文| 综合久久亚洲| 50度灰在线观看| 重囗味另类老妇506070| 成年人深夜视频| 国产一区日韩一区| 黄网站色视频免费观看| 欧美日韩亚洲国产精品| 真实国产乱子伦对白视频| 黄色日韩精品| 麻豆tv在线播放| 91久久黄色| 日本成年人网址| 丝袜诱惑亚洲看片| 福利在线一区二区三区| 美日韩一级片在线观看| 手机免费av片| 国产成人免费视频网站| 日韩精品人妻中文字幕有码| av不卡一区二区三区| 中日韩精品一区二区三区| 久久久久成人黄色影片| 成人黄色短视频| 欧美aa国产视频| 久久综合伊人77777蜜臀| 国产精品久久麻豆| 欧美激情精品久久久久久| 51精品视频| 国产成人精品午夜| 亚洲欧美综合久久久久久v动漫| 亚洲字幕在线观看| 欧美久久香蕉| 视频一区二区三区在线观看| 午夜久久免费观看| 久久99中文字幕| 人人狠狠综合久久亚洲| 国产美女视频免费看| 成人黄色一级视频| 欧美黄色一级生活片| 亚洲丝袜精品丝袜在线| 五月婷婷激情网| 欧美日韩国产高清一区| 亚洲av无码国产精品永久一区| 国产视频欧美视频| 粗大黑人巨茎大战欧美成人| 91国语精品自产拍在线观看性色| 亚洲欧美在线成人| 国产精品久久久对白| 欧美女优在线视频| 免费看污污视频| 国产精品综合色区在线观看| 亚洲欧美手机在线| 99麻豆久久久国产精品免费 | 欧美激情国产在线| 国内精品视频一区二区三区| 美女国产一区二区| 黄色av网址在线观看| 国产精品国模大尺度视频| 韩国av免费观看| 欧美一区二区三区免费在线看| 偷拍自拍在线| 欧美激情亚洲自拍| 亚洲成人1区| 奇米888一区二区三区| 精品动漫av| 久久色在线播放| 日韩私人影院| 麻豆国产va免费精品高清在线| 性欧美1819sex性高清| 国产美女在线精品免费观看| 亚洲精品小说| 簧片在线免费看| www激情久久| 日本三级片在线观看| 欧美一区二区三区精品| av小片在线| 国产成人精品av| 午夜精品福利影院| 日韩欧美不卡在线| 国产盗摄精品一区二区三区在线| 国产精品视频看看| 欧美性极品少妇| 国产免费a∨片在线观看不卡| 久久频这里精品99香蕉| caoporn成人免费视频在线| 亚洲国产欧洲综合997久久| 久久国产日本精品| 在线免费观看a级片| 亚洲国产精品一区二区久久| 国产黄色一区二区| 欧美精品在线免费观看| 国产一区一区| 最近免费观看高清韩国日本大全| 精品在线你懂的| 手机在线免费看毛片| 91麻豆精品国产综合久久久久久 | 99久久久无码国产精品6| 成人的网站免费观看| 国产在线观看你懂的| 精品国一区二区三区| 国模私拍视频在线播放| 国产精品一区二区三区四区五区 | 一区二区三区色| 国产高清在线免费| 欧美黑人性猛交| 精品五月天堂| 日日橹狠狠爱欧美超碰| 91在线看国产| 男人天堂av在线播放| 在线精品国产欧美| 色8久久久久| 8x8x华人在线| 暴力调教一区二区三区| 亚洲伊人成人网| 一区二区国产精品视频| 色综合一区二区日本韩国亚洲| av动漫免费观看| 福利一区二区在线观看| 国产成人愉拍精品久久 | 香蕉久久aⅴ一区二区三区| 91亚洲精品丁香在线观看| 在线日韩av| 亚洲一区视频在线播放| 欧美日韩国产大片| 青草av在线| 女女同性女同一区二区三区91| 日本不卡一区二区三区| 尤物在线免费视频| 亚洲丁香婷深爱综合| 性欧美1819sex性高清| 久久免费精品日本久久中文字幕| 在线视频 91| 在线日韩精品视频| 日本成人手机在线| 黑森林福利视频导航| 国产精品网站在线播放| 亚洲a视频在线观看| 欧美一区二区三区免费视| 欧美国产一级| 中文字幕a在线观看| 欧美三级电影网| 高清电影在线免费观看| 亚洲bbw性色大片| 成人毛片视频在线观看| 狠狠狠狠狠狠狠| 美日韩在线视频| 国产成人一区| 特种兵之深入敌后| 日本黄色一区二区| 国内在线视频| 一区二区三区四区五区视频| 99在线视频精品| ,一级淫片a看免费| 欧美一级大胆视频| 亚洲激情五月| 91网站免费入口| 精品黑人一区二区三区久久| 久久久免费人体| 97成人在线观看视频| 亚洲黄网站在线观看| 国产福利片在线|