面試命中率90%的點 —— MySQL鎖

sunnylovecmc發表於2020-09-29

一、對MySQL的鎖的瞭解

 

當資料庫有併發事務的時候,可能會產生資料的不一致,這時候需要一些機制來保證訪問的次序,鎖機制就是這樣的一個機制。

 

就像酒店的房間,如果大家隨意進出,就會出現多人搶奪同一個房間的情況,而在房間上裝上鎖,申請到鑰匙的人才可以入住並且將房間鎖起來,其他人只有等他使用完畢才可以再次使用。

 

二、隔離級別與鎖的關係

 

在Read Uncommitted級別下,讀取資料不需要加共享鎖,這樣就不會跟被修改的資料上的排他鎖衝突

 

在Read Committed級別下,讀操作需要加共享鎖,但是在語句執行完以後釋放共享鎖。

 

在Repeatable Read級別下,讀操作需要加共享鎖,但是在事務提交之前並不釋放共享鎖,也就是必須等待事務執行完畢以後才釋放共享鎖。

 

SERIALIZABLE 是限制性最強的隔離級別,因為該級別鎖定整個範圍的鍵,並一直持有鎖,直到事務完成。

 

三、按照鎖的粒度分資料庫鎖有哪些?鎖機制與InnoDB鎖演算法

 

在關係型資料庫中,可以按照鎖的粒度把資料庫鎖分為行級鎖(INNODB引擎)、表級鎖(MYISAM引擎)和頁級鎖(BDB引擎 )。

 

  • MyISAM和InnoDB儲存引擎使用的鎖:

 

 

MyISAM採用表級鎖(table-level locking)。

 

InnoDB支援行級鎖(row-level locking)和表級鎖,預設為行級鎖。

 

  • 行級鎖,表級鎖和頁級鎖對比

 

行級鎖:MySQL中鎖定粒度最細的一種鎖,表示只針對當前操作的行進行加鎖。行級鎖能大大減少資料庫操作的衝突。其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分為共享鎖和排他鎖。

 

特點:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。

 

表級鎖:MySQL中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分MySQL引擎支援。最常使用的MyISAM與InnoDB都支援表級鎖定。表級鎖定分為表共享讀鎖(共享鎖)與表獨佔寫鎖(排他鎖)。

 

特點:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖衝突的概率最高,併發度最低。

 

頁級鎖:是MySQL中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但衝突多,行級衝突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。

 

特點:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般

 

四、從鎖的類別上分MySQL都有哪些鎖呢?像上面那樣子進行鎖定豈不是有點阻礙併發效率了

 

從鎖的類別上來講,有共享鎖和排他鎖。

 

共享鎖: 又叫做讀鎖。當使用者要進行資料的讀取時,對資料加上共享鎖。共享鎖可以同時加上多個。

 

排他鎖: 又叫做寫鎖,當使用者要進行資料的寫入時,對資料加上排他鎖。排他鎖只可以加一個,他和其他的排他鎖,共享鎖都相斥。

 

用上面的例子來說就是使用者的行為有兩種,一種是來看房,多個使用者一起看房是可以接受的。一種是真正的入住一晚,在這期間,無論是想入住的還是想看房的都不可以。

 

鎖的粒度取決於具體的儲存引擎,InnoDB實現了行級鎖,頁級鎖,表級鎖。

 

他們的加鎖開銷從大到小,併發能力也是從大到小。

 

五、MySQL中InnoDB引擎的行鎖是怎麼實現的?

 

InnoDB是基於索引來完成行鎖

 

例: select * from tab_with_index where id = 1 for update;

 

for update 可以根據條件來完成行鎖鎖定,並且 ID 是有索引鍵的列,如果 ID不是索引鍵那麼InnoDB將完成表鎖,併發將無從談起

 

六、InnoDB儲存引擎的鎖的演算法有三種

1.Record lock:單個行記錄上的鎖

2.Gap lock:間隙鎖,鎖定一個範圍,不包括記錄本身

3.Next-key lock:record+gap 鎖定一個範圍,包含記錄本身

 

七、相關知識點:

 

Innodb對於行的查詢使用next-key lock

Next-locking keying為了解決Phantom Problem幻讀問題

當查詢的索引含有唯一屬性時,將next-key lock降級為record key

Gap鎖設計的目的是為了阻止多個事務將記錄插入到同一範圍內,而這會導致幻讀問題的產生

 

有兩種方式顯式關閉gap鎖:(除了外來鍵約束和唯一性檢查外,其餘情況僅使用record lock) 

A. 將事務隔離級別設定為RC

B. 將引數innodb_locks_unsafe_for_binlog設定為1

 

八、什麼是死鎖?怎麼解決?

死鎖是指兩個或多個事務在同一資源上相互佔用,並請求鎖定對方的資源,從而導致惡性迴圈的現象。

 

常見的解決死鎖的方法

 

1、如果不同程式會併發存取多個表,儘量約定以相同的順序訪問表,可以大大降低死鎖機會。

2、在同一個事務中,儘可能做到一次鎖定所需要的所有資源,減少死鎖產生概率;

3、對於非常容易產生死鎖的業務部分,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產生的概率;

 

如果業務處理不好可以用分散式事務鎖或者使用樂觀鎖

 

九、資料庫的樂觀鎖和悲觀鎖是什麼?怎麼實現的?

 

資料庫管理系統(DBMS)中的併發控制的任務是確保在多個事務同時存取資料庫中同一資料時不破壞事務的隔離性和統一性以及資料庫的統一性。樂觀併發控制(樂觀鎖)和悲觀併發控制(悲觀鎖)是併發控制主要採用的技術手段。

 

悲觀鎖:假定會發生併發衝突,遮蔽一切可能違反資料完整性的操作。在查詢完資料的時候就把事務鎖起來,直到提交事務。

實現方式:使用資料庫中的鎖機制

 

樂觀鎖:假設不會發生併發衝突,只在提交操作時檢查是否違反資料完整性。在修改資料的時候把事務鎖起來,通過Version的方式來進行鎖定。

實現方式:一般會使用版本號機制或CAS演算法實現。

 

兩種鎖的使用場景

 

從上面對兩種鎖的介紹,我們知道兩種鎖各有優缺點,不可認為一種好於另一種,像樂觀鎖適用於寫比較少的情況下(多讀場景),即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。

 

但如果是多寫的情況,一般會經常產生衝突,這就會導致上層應用會不斷的進行Retry,這樣反倒是降低了效能,所以一般多寫的場景下用悲觀鎖就比較合適。

相關文章