說一說 MySQL的鎖機制(行鎖、表鎖、間隙鎖、Next-Key Lock)

鎖的操做類型分類
  • 讀鎖共享鎖,多個讀操做能夠對同一份數據同時進行而不會互相影響。數據庫

  • 寫鎖排他鎖,在寫操做未完成以前,會阻止其餘的寫鎖與讀鎖。併發

鎖的操做粒度分類
  • 表鎖: 偏向於讀,MyiSAM
  • 行鎖:偏向於寫,InnoDB

MyiSAM

  • 在進行SELECT 操做前,MyiSAM會給涉及到的表加讀鎖。這個時候其餘Session能夠正常對未加鎖的表進行操做。可是對加了讀鎖的表,只能對其進行查詢(共享鎖),對其修改則會阻塞,等待至表解鎖後,纔會生效。高併發

  • Session1 Session2
    給TABLE_A加讀鎖 無操做
    能夠對TABLE_A進行查詢,不能對TABLE_A進行修改 能夠對TABLE_A進行查詢,不能對TABLE_A進行修改
    查詢修改 TABLE_B 報錯 查詢修改 TABLE_B正常
    修改TABLE_A報錯 修改TABLE_A阻塞
    Unlock tables;解鎖 TABLE_A被修改
  • 在進行寫操做前,MyiSAM會給涉及到的表加寫鎖。這個時候其餘Session能夠正常對未加鎖的表進行操做。可是對加了寫鎖的表,對其進行讀或寫,都會阻塞,直至寫鎖釋放後,纔會進行相應操做。post

    • Session1 Session2
      給TABLE_A加寫鎖 無操做
      能夠對TABLE_A進行修改,不能對TABLE_A進行查詢 不能對TABLE_A進行查詢,修改
      不能對TABLE_B進行操做 能夠對TABLE_B進行操做
      查詢TABLE_A報錯 查詢或者修改TABLE_A阻塞
      Unlock tables;解鎖 TABLE_A被查詢出結果或被修改
  • MyiSAM的讀寫鎖調度是寫優先,這也是MyiSAM不適合做爲以寫爲主的引擎。由於寫鎖後,其餘線程不能進行任何操做,大量的寫入操做會使得查詢很可貴到鎖,從而形成永久堵塞。優化



IMPORTANTspa

通俗地講:.net

  • 讀鎖就是:我要備份,後面來的先別亂動(修改)東西;線程

  • 寫鎖就是:我要修改,後面來的別急,排隊(無論你是要讀仍是要改,都得等我此次改完)。設計



InnoDB

InnoDB的鎖機制爲行鎖,行鎖支持事務。code



事務的ACID屬性:
  • A 原子性(Atomic):指一個事務爲最小單位不可再往下劃分,要麼全執行,要麼都不執行。
  • C 一致性(Consistency):指數據在事務執行以前是一致的,執行以後也是一致的,即:不會破壞數據庫的完整性(完整性:邏輯與業務上的符合邏輯即爲完整性)。
  • I 隔離性(Isolation):指事務在執行的過程不會被外界的其餘事務或數據庫操做干擾,數事務執行過程當中的中間態對外不可見。
  • D 持久性(Durability):事務執行完成以後對數據庫的影響是持久的,不會回滾。


併發事務帶來的問題:
  • 更新丟失:多個事務同時更新同一行的數據,而且不知道其餘事務的存在,致使最後有的更新失效(丟失)了。

  • 髒讀:事務在更新數據的過程當中(已經修改了數據還沒有提交),去讀取數據,讀到了中間態的數據,這些數據不符合一致性要求,即爲髒讀。

  • 不可重複讀:在一次的事務操做中,對某一數據進行了兩次(及以上)的讀操做,此時有另外一個事務在兩次讀操做的中間修改了數據,形成了兩次讀取的數據不一樣,即不能夠重複讀(否則數據會不同)。

  • 幻讀:在一次的事務操做中,先讀取了幾行數據後,另外一個事務又增長或刪除了數據,在此以後,此事務又去讀取數據,發現數據憑空生成或消失,跟幻覺同樣,即幻讀。

總結:更新丟失爲多個事務幾乎同時修改數據出現的問題;髒讀爲一個事務在修改數據,另外一個事務讀取(SELECT)事務出現的問題;不可重複讀爲一個事務在查詢數據,中間有另外一個事務修改(UPDATE)了數據的問題;幻讀爲一個事務在查詢數據,另外一個事務在插入或刪除(INSERT or DELETE)數據的問題。



事務的隔離級別:
  • 未提交讀Read Uncommitted:最低級別,只能避免不讀到物理修改數據過程的數據,數據的邏輯修改的中間態依然存在,破壞了數據一致性,上述問題同時存在。
  • 已提交讀Read Committed:語句級,保證了語句的原子性,只能讀到已經提交的內容,可是在修改數據過程當中並無加鎖,爲何只會讀到已經提交的數據內容呢?,這是使用了「快照讀」的方式優化了,使得咱們在修改數據的同時,查詢不會被阻塞,能夠完成高併發的查詢,大大提升了效率;可是由於修改的過程當中沒有加鎖,則會出現兩次查詢數據的過程當中,數據中間被其餘事務修改或者增添數據了,形成不可重複讀和幻讀。
  • 可重複讀Repeated Read:事務級,MySQL默認隔離級別,從名字看就知道了,避免了不可重複讀的問題。普通的查詢一樣是經過「快照讀」的方式,來避免髒讀的出現,在此基礎上又加入了一個在事務開啓的同時,不能對涉及到的數據行進行修改,從而避免了「同一次事務中讀到的數據不一致」的不可重複讀的問題,可是沒有避免幻讀(在InnoDB中解決了幻讀「間隙鎖加行鎖)。
  • 可序列號Serializable:最高級別,事務級,串行執行事務,即一個一個排隊執行事務,這種級別下,全部的併發事務問題都會被避免,可是因爲從並行操做變成了串行排隊操做,效率大大下降。


已提交讀與可重複讀是實際開發中最常用到的兩種事務隔離級別,這二者主要是經過MVCC(Multi Version Concurrency Control對併發事務問題的解決。

  • Read Commited的作法是在事務的每一條SQL語句執行前生成一個快照,此時其餘併發事務去讀取這個數據時,避免了髒讀的出現。
  • Repeated Read的作法是在事務的第一次查詢前生成一個快照,以後在這一次事務的讀取過程當中,都去讀取這一次快照,從而避免了髒讀和不可重複讀。


總結鎖與隔離級別與併發問題的關係:

在默認的隔離級別下,咱們在對某幾行數據進行修改或者查詢的時候,只會鎖住這幾行數據不被修改,從而保證避免了不可重複讀的出現;而咱們即便對整張表全部行都進行操做了,那也是鎖住了這張表的全部行,而不是鎖住這張表,不能阻止表插入新的行,從而依然會出現幻讀的狀況(間隙鎖+行鎖的Next-Key Lock解決了此問題),而最高的隔離級別則是經過將事務串行化,咱們在執行查詢事務的同時是不可能有其餘事務來插入數據的,從而避免了幻讀的出現。



間隙鎖(Gap Lock)

當咱們在查詢語句時,條件爲範圍查詢時,InnoDB無論這個區間是否有數據,都會將其鎖住,向這個區間的「間隙」(不存在的行)插入或刪除數據都會阻塞。



Next-Key Lock

Next-Key Lock = Record Lock + Gap Lock InnoDB在默認隔離級別(Repeated Read)下,使用Next-Key Lock的方案解決了幻讀的問題。

即在進行範圍性的SELECT時,咱們先對已經存在的Records加上Record Lock,再對此區間的間隙加上Gap Lock,從而解決了幻讀的問題。



索引失效會使得行鎖變成表鎖

緣由:索引失效致使的全表掃描,使得從行鎖->表鎖。


如何鎖定一行

select … for update 語句




優化建議

  • 儘量讓全部數據的檢索都經過索引完成,避免無索引行鎖升級爲表鎖。
  • 合理設計索引,儘可能縮小鎖的訪問。
  • 儘量減小檢索條件 避免間隙鎖的危害。
  • 儘可能控制事務大小,減小鎖定資源量和時間長度。
  • 儘量低級別事務隔離。


InnoDB與MyiSAM最大的不一樣點:是InnoDB支持事務、行鎖、外鍵,MyiSAM不支持。具體文章
相關文章
相關標籤/搜索