前阿里數據庫專家總結的MySQL里的各種鎖(下篇)
- 2020 年 3 月 5 日
- 筆記
在上篇中,我們介紹了MySQL中的全局鎖和表鎖。
今天,我們專註於介紹一下行鎖,這個在日常開發和面試中常常困擾我們的問題。
1.行鎖基礎
由於全局鎖和表鎖對增刪改查的性能都會有較大影響,所以,我們自然會想到,
只需要對有修改的行加鎖就行了,這就是行鎖。
在事務中,事務1更新了一行主鍵為1的數據行,那麼,在這個事務釋放鎖之前,事務2是不能操作的。
另外,有一個很多人容易混淆的概念,就是行鎖什麼時候釋放?
搞清這個事情,需要了解什麼叫作 兩階段鎖。
什麼是兩階段鎖呢?舉個例子你就明白了。
這裡事務2執行後會是什麼結果呢?
如果你明白了兩階段鎖的含義,你就會知道,事務2的updat語句會阻塞,直到事務1提交以後才能繼續執行。
所以,這裡再次強調一下,兩階段鎖的含義。
在 InnoDB 事務中,行鎖是在需要的時候才加上的,但並不是語句執行完了了就立刻釋放, 而是要等到事務結束時才釋放。
注意,除了update語句能加寫鎖外,另外,還有一種對select語句加寫鎖的方式,就是
當前讀:Select …. for update
2.行鎖進階
2.1 什麼是幻讀
面試的時候,面試官經常會喜歡問數據庫的事務隔離級別。
大家要能回答出四種隔離級別,四種隔離級別的含義。
再多問一點,會問你什麼是臟讀,什麼是幻讀,哪個隔離級別會解決什麼問題。
首先明確一下,什麼是幻讀?
同樣是一個事務,在事務中前後兩次查詢,出現了不同的結果。
不同之處在於,臟讀是針對update,也就是同一行的數據出現了不一致。
注意,幻讀出現的場景
第一:事務的隔離級別為可重複讀,且是當前讀
第二:幻讀僅專指新插入的行,在範圍查詢中,後一次查詢出現了新的數據行。
2.2 怎麼解決幻讀
這些如果你都能答上,面試官可能會繼續追問,幻讀是怎麼產生的,又是怎麼被解決的。
即使我們給所有update涉及的行都加上了行鎖,還是無法解決新插入的記錄,因為這些記錄原本不存在,自然無法加上行鎖。
那怎麼辦呢?為了解決這個問題,innodb只好引入新的鎖,間隙鎖(Gap Lock)。
“間隙鎖,鎖的是兩個值之間的空隙”。
舉個例子:
在四條記錄,ID=0,10,20,30中,會產生如下的五個間隙範圍
間隙鎖就是對這五個間隙範圍加鎖,防止新的記錄插入。
注意,行鎖的衝突是行與行之間的衝突,是行鎖與行鎖之間的。與間隙鎖衝突的是往“間隙中插入數據”這個操作,間隙鎖本身不會產生衝突。
間隙鎖和行鎖合稱為next-key lock。
每個next-key lock是前開後閉的。間隙鎖本身是前開後開的。
小tips
標準的事務隔離級別中,可重複讀只解決臟讀問題,無法解決幻讀問題。但是在innodb中,用next-key lock解決了幻讀的問題。
3.關於行鎖的優化應用
3.1 兩階段鎖的優化應用
上面的基礎知識中,解釋了什麼是 兩階段鎖。
那麼,對我們業務開發中有什麼借鑒意義呢?
既然我們知道了,行鎖必須在整個事務完全提交後才會釋放,那麼,如果我們的事物中需要鎖住多行,就要把最可能造成鎖衝突,或者是鎖住最多行的語句儘可能地往後放。
舉個例子,小A在線上購買了商家B的一個產品,這個購買的動作可以簡化為3個操作:
1)小A的銀行賬戶餘額扣款x;
2)商家B的銀行賬戶餘額增加x;
3)添加一條交易記錄;
這裡,涉及到兩個update操作,和一個insert操作。為了保證交易的原子性,將三個動作放在了一個事務中。
那怎麼安排三個語句的先後順序呢?如果不仔細考慮,那麼就可能是隨意選個123或者213的順序了。
仔細想想呢?
顯然,這裡最容易造成衝突的是步驟2),可能同時有多個用戶購買商家B的產品,然後需要給商家B的餘額做update操作。
另外,步驟3)是insert操作,最不容易出現鎖衝突。
所以,最好的步驟順序是3)-> 1) -> 2),將最容易產生衝突的操作放在最後執行,那麼會比2)->1) ->3)的順序,大大提高並發度。
3.2 間隙鎖的問題與優化
間隙鎖的引入也帶來了一些新的問題,比如:降低並發度,可能導致死鎖。
因為間隙鎖的引入,可能會導致同樣的語句鎖住了更大的範圍。
那怎麼辦呢?
注意,間隙鎖在可重複讀級別下才是有效的。
所以,只要我們的業務不需要可重複讀的保證,我們就可以把隔離級別設置為讀提交(也是阿里雲rds數據庫的默認隔離級別),就沒有間隙鎖了。
然後,為了解決可能的數據和日誌不一致的問題,需要把binlog格式設置為row。
讀提交級別 + binlog的row格式,也是一般公司數據庫的標準配置。
現在,你知道原因了吧:)
參考:
丁奇《MySQL 實戰45講》
看到這裡了,原創不易,點個關注、點個贊吧,你最好看了~
知識碎片重新梳理,構建Java知識圖譜:https://github.com/saigu/JavaKnowledgeGraph(歷史文章查閱非常方便)
掃碼關注我的公眾號“阿丸筆記”,第一時間獲取最新更新。同時可以免費獲取海量Java技術棧電子書、各個大廠面試題。