精品欧美一区二区三区在线观看 _久久久久国色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)

羞羞的视频在线观看| 亚洲国产美女视频| 在线观看涩涩| 国产日韩欧美a| 91精品久久久久久久久久入口| 91制片厂在线| 婷婷综合电影| 欧美精品在线一区二区三区| 91视频成人免费| 亚洲av片在线观看| 国产一区二区免费看| 97国产suv精品一区二区62| 久久丫精品忘忧草西安产品| 香蕉成人app| 在线免费视频一区二区| 日韩在线观看a| 成黄免费在线| 97se亚洲国产综合在线| 国产日韩欧美在线| 成人免费毛片男人用品| 亚洲精品国产成人影院| 亚洲毛片在线看| 动漫av在线免费观看| 日韩欧美精品一区二区综合视频| 亚洲国产精品自拍| 在线天堂一区av电影| 免费一级毛片在线观看| 国产成人一区二区精品非洲| 国产女精品视频网站免费| 欧美卡一卡二卡三| 日韩欧美一区二区三区在线视频 | 日韩精品一卡二卡| 欧美顶级大胆免费视频| 日韩精品在线第一页| 日本女人性视频| 亚洲欧美专区| 欧美性极品少妇| 色综合av综合无码综合网站| ****av在线网毛片| 一区二区三区在线观看国产 | 日本不卡不卡| 国产色一区二区| 九九九久久久| 亚洲av成人精品毛片| 粉嫩蜜臀av国产精品网站| 91影院在线免费观看视频| 在线免费观看视频网站| 蜜臀91精品一区二区三区| 日本久久久a级免费| 国产精品视频免费播放| 亚洲一区日韩在线| 国产91ⅴ在线精品免费观看| 国产微拍精品一区| 免费欧美日韩| 日本一区二区不卡| 国产主播第一页| 日韩成人av影视| 国产精品日韩在线播放| 中文字幕在线一| 另类小说综合欧美亚洲| 91久久久久久久久久| 国产精品伦理一区| 国产精品一区久久久久| 大波视频国产精品久久| 四虎永久在线观看| www国产精品av| 日韩一区二区三区资源| 天堂网av2018| 久久高清免费| 九九热这里只有精品6| 欧美日韩在线视频免费播放| 激情综合网址| 91大神在线播放精品| 潘金莲一级淫片aaaaaa播放| 免费观看成人av| 亚洲www永久成人夜色| 亚洲产国偷v产偷v自拍涩爱| 99久久婷婷国产综合精品 | 亚洲 欧美 激情 小说 另类| 久久久蜜桃精品| 亚洲欧美久久久久一区二区三区| 男人影院在线观看| 亚洲国产中文字幕在线视频综合| 阿v天堂2017| 91p九色成人| 日韩三级.com| theav精尽人亡av| 亚洲视频资源| 欧美va在线播放| 成年人网站免费在线观看| 精品国产一区二区三区噜噜噜| 日日狠狠久久偷偷四色综合免费| 69av.com| 日韩精品一级二级| 91手机在线观看| 免费在线稳定资源站| 亚洲人午夜精品天堂一二香蕉| 日本久久久网站| 91精品影视| 精品盗摄一区二区三区| 欧美一区二区三区粗大| 欧美午夜国产| 国产日韩欧美成人| 无码国产精品高潮久久99| 国产精品网站在线| 成人在线观看你懂的| 日韩成人在线一区| 亚洲国产天堂久久国产91| 国产精品理论在线| 亚洲资源av| 成人综合av网| 国产理论在线观看| 欧洲精品中文字幕| 妖精视频一区二区| 一区二区电影在线观看| 国产成人涩涩涩视频在线观看| 精品久久久无码中文字幕| 欧美国产精品劲爆| 97超碰青青草| 国产成人澳门| 久久成人18免费网站| 成人免费毛片视频| 26uuu色噜噜精品一区| wwwwww欧美| 奇米一区二区| 精品国产一区久久久| 国产美女www爽爽爽| 92国产精品观看| 男人天堂av片| 日韩欧美中文在线观看| 日韩视频免费大全中文字幕| 日韩精品一区二区亚洲av| caoporm超碰国产精品| 日本福利视频在线观看| 韩国一区二区三区视频| 久久精品国产一区二区电影| 中文字幕在线视频免费| 国产精品情趣视频| 在线免费观看av的网站| 日本久久黄色| 国产裸体写真av一区二区| 黄色av网站在线看| 91福利精品视频| 亚洲最大成人网站| 视频一区中文字幕国产| 精品久久sese| 日韩电影毛片| 亚洲人成伊人成综合网久久久| 日韩手机在线观看| 91一区一区三区| 欧美在线观看视频网站| 成人av国产| 成人xxxx视频| 性xxxfreexxxx性欧美| 精品捆绑美女sm三区| 精品一区免费观看| 91在线小视频| 欧美精品一区二区三区免费播放| 国产欧美亚洲精品a| 国产一区二区色| 国产激情在线| 亚洲精品一线二线三线无人区| 免费人成在线观看| 99免费精品视频| 亚洲色图38p| 国产精品成久久久久| 91最新在线免费观看| 欧美韩日亚洲| 亚洲精品丝袜日韩| 中文字幕乱码一区二区| 一区二区三区日韩欧美精品| 欧美肉大捧一进一出免费视频| 国产精品社区| 一区精品视频| 国产精品久久久久久久久久白浆| 欧美一区亚洲一区| 欧美一区二区三区| 亚洲成人精品久久久| 久久久精品毛片| 亚洲欧美日韩成人高清在线一区| 69亚洲乱人伦| 丝袜亚洲另类欧美| 大地资源网在线观看免费官网 | 免费av一区二区三区| 丁香婷婷久久| 久久久欧美一区二区| 国产色在线 com| 日韩女同互慰一区二区| 永久免费无码av网站在线观看| 国产精品久久久久久久久搜平片 | 四季av一区二区三区| 激情成人综合| 亚洲国产精品一区在线观看不卡 | 免费99视频| 国产日韩一区二区三免费高清| 91精品国产高清久久久久久久久| 在线激情免费视频| 日韩国产高清视频在线| 国产精品视频在线观看免费| 日韩欧美国产视频| 国内偷拍精品视频| 国产精品久久久久三级| 中文字幕在线永久| 国产一区二区在线看| 激情网站五月天| 国内精品福利| 中文字幕欧美日韩一区二区三区| 日韩三级av| 懂色中文一区二区三区在线视频| 精品欧美日韩精品| 欧日韩不卡在线视频| 五月天激情在线| www亚洲欧美| 国产精品视频二区三区| 日韩av在线网页| 亚洲经典一区二区| 欧美一区二区三区人| 日韩久久久久久久久久| 精品久久久精品| 青娱乐在线视频免费观看| 亚洲欧美怡红院| 国产黄色大片免费看| 91色乱码一区二区三区| 国产精九九网站漫画| 国产一区激情在线| 天天影视色综合| 久久国产精品免费| 韩国中文字幕av| 日韩和欧美一区二区三区| 欧美一区二区中文字幕| 在线看片成人| 成人免费视频91| 欧美久久久久| 成人小视频在线观看免费| 91成人免费| 中文字幕一区二区三区乱码 | 欧美激情一区二区三区久久久| 免费黄色在线观看| 色综合影院在线| 尤物视频在线免费观看| 色综久久综合桃花网| 在线播放麻豆| 日韩在线观看av| 成人a在线视频免费观看| 欧美成人中文字幕| 亚洲区欧洲区| 欧美精品久久久久a| 少妇视频在线| 97在线视频国产| 午夜伦理福利在线| 国产成人精品电影| 黄色日韩网站| 亚洲www视频| 国产精品久久久久久久久久白浆| 国产视频在线观看一区| 午夜欧洲一区| 色播亚洲视频在线观看| 一本一道波多野毛片中文在线| 日韩国产欧美精品一区二区三区| 熟妇人妻av无码一区二区三区| 日韩av影院在线观看| 你懂的视频在线| 在线日韩日本国产亚洲| 免费在线看黄网站| 九九综合九九综合| 国产极品在线观看| 国产精品91在线| 在线免费观看亚洲| 国产精品成人一区二区三区| 美女视频免费精品| 欧美日韩综合精品| 99九九热只有国产精品| 精品免费久久久久久久| 国产婷婷精品| 亚洲欧美自偷自拍另类| 国产精品18久久久久久久网站| jjzzjjzz欧美69巨大| 久久久精品国产免费观看同学| 欧美a在线播放| 亚洲在线成人精品| 精品免费囯产一区二区三区 | 亚洲三级视频网站| 国产剧情一区二区三区| 国产麻豆剧传媒精品国产av| 久久免费精品国产久精品久久久久 | 成人污网站在线观看| 国一区二区在线观看| 熟女少妇精品一区二区| 国产乱子伦视频一区二区三区| 国产精品一区二区人妻喷水| 国产欧美日韩在线观看| 久久久精品视频在线| 在线亚洲高清视频| 亚洲精品字幕在线| 日韩中文视频免费在线观看| 成年人视频免费在线播放| 国产精品久久久久久久久久尿 | sm久久捆绑调教精品一区| 国产精品久久久久久久久久东京| 成人免费在线电影网| 亚洲精品久久区二区三区蜜桃臀| 欧美日韩国产高清| 色乱码一区二区三区在线| www.性欧美| 黄色一级片中国| 欧美吞精做爰啪啪高潮| 色综合久久久久久| 欧美成人性色生活仑片| 日韩制服一区| 欧美亚州在线观看| 在线欧美一区| 一区二区三区人妻| 一区免费观看视频| 午夜精品久久久久久久蜜桃| 精品欧美一区二区久久| 激情影院在线观看| 国产精品入口夜色视频大尺度| 视频小说一区二区| 成人午夜视频在线观看免费| 国产在线日韩欧美| 欧美一区二区三区粗大| 日韩欧美在线中文字幕| 日本黄色不卡视频| 欧美第一淫aaasss性| 在线成人免费| 中文字幕一区二区三区四区五区 | 调教视频免费在线观看| 国产成人精品a视频一区www| 亚洲老女人视频免费| 精品国产免费av| 91网页版在线| 国产真实乱偷精品视频| 欧美va在线播放| 国内高清免费在线视频| 粉嫩av四季av绯色av第一区| 中文字幕一区二区三区久久网站| 91av视频免费观看| 最好看的中文字幕久久| 国产在成人精品线拍偷自揄拍| 日韩在线免费av| 日韩专区视频网站| 免费国产成人看片在线| 国产伦精品一区二区三区免费| 2018天天弄| 欧美成人一区二区三区片免费| 中文字幕在线三区| 99国产在线视频| 136国产福利精品导航网址| 99精品一区二区三区无码吞精| 亚洲国产精品久久久男人的天堂| 不卡av中文字幕| 久久久久久久久久久国产| 精品一区二区男人吃奶| 欧美亚洲国产成人| 久久久久久久久久久久久女国产乱| 欧美a视频在线观看| 最新的欧美黄色| 欧美另类中文字幕| 黄色一级视频在线播放| 99久久综合精品| 中文字幕一区二区人妻痴汉电车| 在线国产精品播放| 国产一区二区三区国产精品| 乱熟女高潮一区二区在线| 99久久免费精品| 波多野结衣日韩| 久久亚洲国产精品成人av秋霞| 日韩精品视频一区二区三区| 男人日女人逼逼| 日本一区二区成人在线| aa视频在线免费观看| 国内揄拍国内精品少妇国语| 欧美女优在线视频| 亚洲第一天堂久久| 午夜精品久久久久久久蜜桃app| 免费成人av电影| 91免费视频国产| 99国产精品99久久久久久粉嫩| 久久只有这里有精品| 538prom精品视频线放| 9999在线视频| 亚洲欧洲一区二区| 成人国产精品免费观看| 中文av免费观看| 久久久久久久久爱| 波多野结衣一区| 男人添女人荫蒂国产| 在线视频欧美区| 里番在线播放| 五月天色一区| 成年人午夜久久久| 91欧美日韩麻豆精品| 97精品国产97久久久久久免费| 欧美日韩精品在线一区| 国产伦精品一区二区三区88av| 欧美午夜精品久久久久久超碰| 久久一卡二卡| 在线精品亚洲一区二区| 久久久久亚洲综合| 国产黄色av网站|