面试让HR都能听懂的MySQL锁机制,欢声笑语中搞懂MySQL锁
騰訊云數據庫負責人林曉斌說過:“我們面試MySQL同事時只考察兩點,索引和鎖”。言簡意賅,MySQL鎖的重要性不言而喻。
本文通過同事“僑總”的一場面試,帶你通俗易懂的掌握MySQL各種鎖機制,希望可以幫到你!近期會繼續整理深入性的鎖機制文章,有興趣的老鐵,記得關注一下,到時叫你~
今天的主人公是我們公司同事僑總,傳說中手上有10個比特幣的男人。自從比特幣大漲以來,養成了幾個小愛好:周末聽戲坐包廂,騎馬酒吧滑雪場。
這不,前兩天僑總又雙叒叕出來體驗面試了,晚上請我燒烤時跟我聊了聊這次有趣的面試經歷,真是意猶未盡,趁他回味之余我又吃了十幾串兒腰子和羊肉~ 嗯,真香!
對不住,跑題了。。人到中年嘛,保溫杯里泡枸杞之余總會。。。
來不及解釋了,快上車!
大家好,我是陳哈哈的同事“僑總”,領導一般不敢喊我名字,都叫我小僑~
下面是我的一次面試經歷,面試官是技術經理和HR,大家吃好喝好~
僑總:馬…小馬哥好!
面試官:你好,小僑啊,看你簡歷寫著精通MySQL鎖,你認為精通應該是啥水平呢?
僑總:馬哥我是個老實人,我認為精通就是,比面試官知道的多就完了。。
面試官:(怎么有種似曾相識的感覺?《聽我講完redo log、binlog原理,面試官老臉一紅》)
面試官:行,那你先給我說說MySQL設計這個鎖是干啥用的呀?
僑總:數據庫鎖設計的初衷是處理并發問題。作為多用戶共享的資源,當出現并發訪問的時候,為了保證數據的一致性,數據庫需要合理地控制資源的訪問規則。而鎖就是用來實現這些訪問規則的重要機制。
簡單說,數據表就像公共廁所。emmm…換個下飯的說法,數據表就好比您開的一家酒店,而每行數據就像酒店的房間,如果大家隨意進出,就會出現多人搶奪同一個房間的情況,而在房間上裝上鎖,申請到鑰匙的人才可以入住并且將房間鎖起來,其他人只有等他用完退房后才可以再次使用,這樣保證了房間的一致性,方便酒店進行管理。
MySQL鎖機制的初衷便是如此,當然,MySQL數據庫由于其自身架構的特點,存在多種數據存儲引擎,每種存儲引擎所針對的應用場景特點都不太一樣,為了滿足各自特定應用場景的需求,每種存儲引擎的鎖定機制都是為各自所面對的特定場景而優化設計,所以各存儲引擎的鎖定機制也有較大區別。
面試官:嗯,那你說一下MySQL都分為哪些鎖。
僑總:
面試官:袁芳你怎么看?
HR小姐姐:。。。
面試官:小僑啊,那你來談一談你對表鎖、行鎖的理解吧。
表鎖
僑總:表級別的鎖定是MySQL各存儲引擎中最大顆粒度的鎖定機制。該鎖定機制最大的特點是實現邏輯非常簡單,帶來的系統負面影響最小。所以獲取鎖和釋放鎖的速度很快。由于表級鎖一次會將整個表鎖定,所以可以很好的避免困擾我們的死鎖問題。
當然,鎖定顆粒度大所帶來最大的負面影響就是出現鎖定資源爭用的概率也會最高,大大降低并發度。
使用表級鎖定的主要是MyISAM,MEMORY,CSV等一些非事務性存儲引擎。
行鎖
僑總:與表鎖正相反,行鎖最大的特點就是鎖定對象的顆粒度很小,也是目前各大數據庫管理軟件所實現的鎖定顆粒度最小的。由于鎖定顆粒度很小,所以發生鎖定資源爭用的概率也最小,能夠給予應用程序盡可能大的并發處理能力從而提高系統的整體性能。
雖然能夠在并發處理能力上面有較大的優勢,但是行級鎖定也因此帶來了不少弊端。由于鎖定資源的顆粒度很小,所以每次獲取鎖和釋放鎖需要做的事情也更多,帶來的消耗自然也就更大了。此外,行級鎖定也最容易發生死鎖。
使用行級鎖定的主要是InnoDB存儲引擎。
- 適用場景:從鎖的角度來說,表級鎖更適合于以查詢為主,只有少量按索引條件更新數據的應用,如Web應用;而行級鎖則更適合于有大量按索引條件并發更新數據的情況,同時又有并發查詢的應用場景。
頁鎖
除了表鎖、行鎖外,MySQL還有一種相對偏中性的頁級鎖,頁鎖是MySQL中比較獨特的一種鎖定級別,在其他數據庫管理軟件中也并不是太常見。頁級鎖定的特點是鎖定顆粒度介于行級鎖定與表級鎖之間,所以獲取鎖定所需要的資源開銷,以及所能提供的并發處理能力也同樣是介于上面二者之間。另外,頁級鎖定和行級鎖定一樣,會發生死鎖。
使用頁級鎖定的主要是BerkeleyDB存儲引擎。
面試官:那全局鎖是什么時候用的呢?
全局鎖
僑總:首先全局鎖,是對整個數據庫實例加鎖。使用場景一般在全庫邏輯備份時。
MySQL提供加全局讀鎖的命令:Flush tables with read lock (FTWRL)
這個命令可以使整個庫處于只讀狀態。使用該命令之后,數據更新語句、數據定義語句和更新類事務的提交語句等修改數據庫的操作都會被阻塞。
風險:
還有一種鎖全局的方式:set global readonly=true ,相當于將整個庫設置成只讀狀態,但這種修改global配置量級較重,和全局鎖不同的是:如果執行Flush tables with read lock 命令后,如果客戶端發生異常斷開,那么MySQL會自動釋放這個全局鎖,整個庫回到可以正常更新的狀態。但將庫設置為readonly后,客戶端發生異常斷開,數據庫依舊會保持readonly狀態,會導致整個庫長時間處于不可寫狀態,試想一下微信只能看,不能打字~~
HR小姐姐:那微信不就完蛋了?
僑總:是啊,抓緊找老實人背鍋!
面試官:不錯,你把這幾種鎖的側重點都表述清楚了。那你再說一下你對不同級別的那幾種鎖的使用場景和理解吧?
僑總:MySQL基于鎖級別又分為:共享(讀)鎖、排他(寫)鎖、意向共享(讀)鎖、意向排他(寫)鎖
共享(讀)鎖、排他(寫)鎖、意向共享(讀)鎖、意向排他(寫)鎖
僑總:對于共享(讀)鎖、排他(寫)鎖,比如咱們住酒店,入住前顧客都是有權看房的,只看不住想白嫖都是可以的,前臺小姐姐會把門給你打開。當然,也允許不同的顧客一起看(共享 讀),比如和這位殺馬特小伙子。
看房時房間相當于公共場所,小姐姐囑咐不能亂涂亂畫,也不能偷喝免費的礦泉水。。如果你覺得不錯,偷偷跑到前臺要定這間房,交錢后會給你這個房間的鑰匙并將房間狀態改為已入住,不再允許其他人看房(排他 寫)。
對了,當辦理入住時前臺小姐姐也會通知看房的殺馬特小伙子說這間房已經有人定了!!等看房的殺馬特小伙兒罵罵咧咧出門后,看到滿頭大汗的你,鄙夷著咽了一口口水,咳tui!然后你鎖上門哼著歌兒,開始干那些見不得人的事兒~~直到你退房前,其他人無法在看你的房。
可見,讀鎖是可以并發獲取的(共享的),而寫鎖只能給一個事務處理(排他的)。當你想獲取寫鎖時,需要等待之前的讀鎖都釋放后方可加寫鎖;而當你想獲取讀鎖時,只要數據沒有被寫鎖鎖住,你都可以獲取到讀鎖,然后去看房。
另外還有意向讀\寫鎖,嚴格來說他們并不是一種鎖,而是存放表中所有行鎖的信息。就像我們在酒店,當我們預定一個房間時,就對該行(房間)添加 意向寫鎖,但是同時會在酒店的前臺對該行(房間)做一個信息登記(旅客姓名、男女、住多長時間、家里幾頭牛等)。大家可以把意向鎖當成這個酒店前臺,它并不是真正意義上的鎖(鑰匙),它維護表中每行的加鎖信息,是共用的。后續的旅客通過酒店前臺來看哪個房間是可選的,那么,如果沒有意圖鎖,會出現什么情況呢?假設我要住房間,那么我每次都要到每一個房間看看這個房間有沒有住人,顯然這樣做的效率是很低下的。殺馬特小伙兒表示支持!
讀寫鎖、意向鎖的兼容性如下所示;
| 讀鎖 | 兼容 | 沖突 | 兼容 | 沖突 |
| 寫鎖 | 沖突 | 沖突 | 沖突 | 沖突 |
| 意向讀鎖 | 兼容 | 沖突 | 兼容 | 兼容 |
| 意向寫鎖 | 沖突 | 沖突 | 兼容 | 兼容 |
僑總:再回到MySQL原理上講
1 共享(讀)鎖(Share Lock)
共享鎖,又叫讀鎖,是讀取操作(SELECT)時創建的鎖。其他用戶可以并發讀取數據,但在讀鎖未釋放前,也就是查詢事務結束前,任何事務都不能對數據進行修改(獲取數據上的寫鎖),直到已釋放所有讀鎖。
如果事務A對數據B(1024房)加上讀鎖后,則其他事務只能對數據B上加讀鎖,不能加寫鎖。獲得讀鎖的事務只能讀數據,不能修改數據。
SQL顯示加鎖寫法:
SELECT … LOCK IN SHARE MODE;在查詢語句后面增加LOCK IN SHARE MODE,MySQL就會對查詢結果中的每行都加讀鎖,當沒有其他線程對查詢結果集中的任何一行使用寫鎖時,可以成功申請讀鎖,否則會被阻塞。其他線程也可以讀取使用了讀鎖的表,而且這些線程讀取的是同一個版本的數據。
2 排他(寫)鎖(Exclusive Lock)
排他鎖又稱寫鎖、獨占鎖,如果事務A對數據B加上寫鎖后,則其他事務不能再對數據B加任何類型的鎖。獲得寫鎖的事務既能讀數據,又能修改數據。
SQL顯示加鎖寫法:
SELECT … FOR UPDATE;在查詢語句后面增加FOR UPDATE,MySQL 就會對查詢結果中的每行都加寫鎖,當沒有其他線程對查詢結果集中的任何一行使用寫鎖時,可以成功申請寫鎖,否則會被阻塞。另外成功申請寫鎖后,也要先等待該事務前的讀鎖釋放才能操作。
3 意向鎖(Intention Lock)
意向鎖屬于表級鎖,其設計目的主要是為了在一個事務中揭示下一行將要被請求鎖的類型。InnoDB 中的兩個表鎖:
- 意向共享鎖(IS):表示事務準備給數據行加入共享鎖,也就是說一個數據行加共享鎖前必須先取得該表的IS鎖;
- 意向排他鎖(IX):類似上面,表示事務準備給數據行加入排他鎖,說明事務在一個數據行加排他鎖前必須先取得該表的IX鎖。
意向鎖是 InnoDB 自動加的,不需要用戶干預。
再強調一下,對于INSERT、UPDATE和DELETE,InnoDB 會自動給涉及的數據加排他鎖;對于一般的SELECT語句,InnoDB 不會加任何鎖,事務可以通過以下語句顯式加共享鎖或排他鎖。
共享鎖:SELECT … LOCK IN SHARE MODE;
排他鎖:SELECT … FOR UPDATE;
面試官:(這小子有兩下子)嗯,袁芳你怎么看?
HR:通俗易懂,我聽懂了~~
面試官:好,那最后一個問題,你上面提到了樂觀鎖和悲觀鎖,談談你對它的看法吧。
僑總:其實悲觀鎖和樂觀鎖,也并不是 MySQL 或者數據庫中獨有的概念,而是并發編程的基本概念。主要區別在于,操作共享數據時,“悲觀鎖”即認為數據出現沖突的可能性更大,而“樂觀鎖”則是認為大部分情況不會出現沖突,進而決定是否采取排他性措施。
反映到 MySQL 數據庫應用開發中,悲觀鎖一般就是利用類似 SELECT … FOR UPDATE 這樣的語句,對數據加鎖,避免其他事務意外修改數據。樂觀鎖則與 Java 并發包中的 AtomicFieldUpdater 類似,也是利用 CAS 機制,并不會對數據加鎖,而是通過對比數據的時間戳或者版本號,來實現樂觀鎖需要的版本判斷。
MySQL的多版本并發控制 (MVCC),其本質就可以看作是種樂觀鎖機制,而排他性的讀寫鎖、兩階段鎖等則是悲觀鎖的實現。
面試官:好,小僑我看你對MySQL鎖這塊兒確實研究得比較透徹,連HR都聽懂了,還是讓我比較滿意的。
面試官:你平時有什么愛好么?
僑總:我除了周末聽戲坐包廂,騎馬酒吧滑雪場。就是喜歡炒比特幣啦!
面試官:哦,不好意思,我們公司反對炒比特幣的行為,回去等通知吧。
僑總:???
說著面試官馬經理走出了會議室,HR小姐姐表示我哪壺不開提哪壺,馬老板高點買的比特幣,現在泡沫炸了,虧成馬,老板都差點虧沒了。
總結
以上是生活随笔為你收集整理的面试让HR都能听懂的MySQL锁机制,欢声笑语中搞懂MySQL锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线性规划之单纯形法(2)
- 下一篇: 深入理解static关键字