天天看點

mysql資料庫的鎖機制0、鎖1、MySQL中的鎖2、InnoDB中的鎖3、鎖帶來的問題4、死鎖

mysql資料庫的鎖機制

  • 0、鎖
  • 1、MySQL中的鎖
    • 1.1、鎖的類型
    • 1.2、鎖的粒度
    • 表鎖
    • 行鎖
    • 頁鎖
    • 總結
  • 2、InnoDB中的鎖
    • 意向鎖
    • 行鎖的算法
    • 一緻性非鎖定讀
    • 一緻性鎖定讀
  • 3、鎖帶來的問題
  • 4、死鎖

0、鎖

鎖,在計算機中,是協調多個程序或縣城并發通路某一資源的一種機制。

在資料庫當中,除了傳統的計算資源(CPU、RAM、I/O等等)的争用之外,資料也是一種供許多使用者共享通路的資源。如何保證資料并發通路的一緻性、有效性,是所有資料庫必須解決的一個問題,鎖的沖突也是影響資料庫并發通路性能的一個重要因素。

經典原文之談談MySQL的鎖

1、MySQL中的鎖

mysql中的鎖有lock和latch兩種概念:

Latch成為闩(shuan)鎖(輕量級的鎖),工作在記憶體InnoDB緩沖池中,用來給緩沖池中的熱點資料(連結清單)進行加鎖,鎖定時間要求非常短。若時間長,則應用性能會非常差;

在InnoDB中,Latch分為mutex(互斥量)和rwlock(讀寫鎖)。其目的是用來保證并發線程操作臨界資源的正确性,并且通常沒有死鎖檢測的機制。

Latch更詳細的講解可以參考:

LATCH(闩鎖)——易産生的問題以及原因分析

關于MySQL latch争用深入分析與判斷

Lock的對象是事務,用來鎖定的是資料庫中的對象,如表、頁、行。

并且一般lock的對象僅在事務commit或rollback後進行釋放(不同僚務隔離級别釋放的時間可能不同)。

1.1、鎖的類型

對資料的操作其實隻有兩種,也就是讀和寫,InnoDB 實作了标準的行級鎖,也就是共享鎖(Shared Lock)和互斥鎖(Exclusive Lock)。

共享鎖(讀鎖),允許事務讀一行資料。

排他鎖(寫鎖,又叫互斥鎖),允許事務删除或更新一行資料。

因為共享鎖代表了讀操作、互斥鎖代表了寫操作,是以我們可以在資料庫中并行讀,但是隻能串行寫,隻有這樣才能保證不會發生線程競争,實作線程安全。

1.2、鎖的粒度

Lock鎖根據粒度主要分為表鎖、頁鎖和行鎖。不同的存儲引擎擁有的鎖粒度都不同,如MyISAM的表鎖,InnoDB的行鎖;

表鎖

表級别的鎖定是MySQL各存儲引擎中最大顆粒度的鎖定機制。

表鎖的好處:表鎖機制最大的特點是實作邏輯非常簡單,帶來的系統負面影響最小。

是以擷取鎖和釋放鎖的速度很快。由于表級鎖一次會将整個表鎖定,是以可以很好的避免困擾我們的死鎖問題。

表鎖的缺點:鎖定顆粒度大所帶來最大的負面影響就是出現鎖定資源争用的機率也會最高,緻使并發度大打折扣。

表鎖使用場景:使用表級鎖定的主要是MyISAM,MEMORY,CSV等一些非事務性存儲引擎。

行鎖

行級鎖定最大的特點就是鎖定對象的粒度很小,也是目前各大資料庫管理軟體所實作的鎖定顆粒度最小的。

行鎖優點:由于鎖定顆粒度很小,是以發生鎖定資源争用的機率也最小,能夠給予應用程式盡可能大的并發處理能力而提高一些需要高并發應用系統的整體性能。

行鎖缺點:雖然能夠在并發處理能力上面有較大的優勢,但是行級鎖定也是以帶來了不少弊端。由于鎖定資源的顆粒度很小,是以每次擷取鎖和釋放鎖需要做的事情也更多,帶來的消耗自然也就更大了。

此外,行級鎖定也最容易發生死鎖。

行鎖使用場景:使用行級鎖定的主要是InnoDB等事務型存儲引擎。

頁鎖

頁級鎖定是MySQL中比較獨特的一種鎖定級别,在其他資料庫管理軟體中也并不是太常見。

頁級鎖定的特點是鎖定顆粒度介于行級鎖定與表級鎖之間,是以擷取鎖定所需要的資源開銷,以及所能提供的并發處理能力也同樣是介于上面二者之間。

另外,頁級鎖定和行級鎖定一樣,會發生死鎖。

在資料庫實作資源鎖定的過程中,随着鎖定資源顆粒度的減小,鎖定相同資料量的資料所需要消耗的記憶體數量是越來越多的,實作算法也會越來越複雜。不過,随着鎖定資源顆粒度的減小,應用程式的通路請求遇到鎖等待的可能性也會随之降低,系統整體并發度也随之提升。

頁鎖使用場景:使用頁級鎖定的主要是BerkeleyDB存儲引擎

總結

表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的機率最高,并發度最低。

行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的機率最低,并發度也最高。

頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般。

從鎖的角度來說,表級鎖更适合于以查詢為主,隻有少量按索引條件更新資料的應用,如Web應用;而行級鎖則更适合于有大量按索引條件并發更新少量不同資料,同時又有并發查詢的應用,如一些線上事務處理(OLTP)系統。

2、InnoDB中的鎖

意向鎖

上節提到InnoDB 支援多種粒度的鎖,也就是行鎖和表鎖。為了支援多粒度鎖定,InnoDB 存儲引擎引入了意向鎖(Intention Lock)。

那什麼是意向鎖呢?我們在這裡可以舉一個例子:如果沒有意向鎖,當已經有人使用行鎖對表中的某一行進行修改時,如果另外一個請求要對全表進行修改,那麼就需要對所有的行是否被鎖定進行掃描,在這種情況下,效率是非常低的;

不過,在引入意向鎖之後,當有人使用行鎖對表中的某一行進行修改之前,會先為表添加意向互斥鎖(IX),再為行記錄添加互斥鎖(X),在這時如果有人嘗試對全表進行修改就不需要判斷表中的每一行資料是否被加鎖了,隻需要通過等待意向互斥鎖被釋放就可以了。

與上一節中提到的兩種鎖的種類相似的是,意向鎖也分為兩種:

意向共享鎖(IS):事務想要在獲得表中某些記錄的共享鎖,需要在表上先加意向共享鎖。

意向互斥鎖(IX):事務想要在獲得表中某些記錄的互斥鎖,需要在表上先加意向互斥鎖。

意向鎖其實不會阻塞全表掃描之外的任何請求,它們的主要目的是為了表示是否有人請求鎖定表中的某一行資料。

行鎖的算法

InnoDB存儲引擎有3種行鎖的算法,其分别是:

Record Lock:單個行記錄上的鎖。

Gap Lock:間隙鎖,鎖定一個範圍,但不包含記錄本身。

Next-Key Lock:Gap Lock+Record Lock,鎖定一個範圍,并且鎖定記錄本身。

Record Lock總是會去鎖住索引記錄,如果InnoDB存儲引擎表在建立的時候沒有設定任何一個索引,那麼這時InnoDB存儲引擎會使用隐式的主鍵來進行鎖定。

Gap Lock的作用是為了阻止多個事務将記錄插入到同一個範圍内,設計它的目的是用來解決Phontom Problem(幻讀問題)。在MySQL預設的隔離級别(Repeatable Read)下,InnoDB就是使用它來解決幻讀問題。

mysql間隙鎖連結

幻讀是指在同一事務下,連續執行兩次同樣的SQL語句可能導緻不同的結果,第二次的SQL可能會傳回之前不存在的行,也就是第一次執行和第二次執行期間有其他事務往裡插入了新的行。

Next-Key Lock是結合了Gap Lock和Record Lock的一種鎖定算法,在Next-Key Lock算法下,InnoDB對于行的查詢都是采用這種鎖定算法。

一緻性非鎖定讀

一緻性非鎖定讀(consistent nonlocking read)是指InnoDB存儲引擎通過多版本控制(MVCC)的方式來讀取目前執行時間資料庫中行的資料。如果讀取的這行正在執行DELETE或UPDATE操作,這時讀取操作不會向XS鎖一樣去等待鎖釋放,而是會去讀一個快照資料。

在事務隔離級别RC和RR下,InnoDB存儲引擎使用非鎖定的一緻性讀。然而對于快照資料的定義卻不同,在RC級别下,對于快照資料,非一緻性讀總是讀取被鎖定行的最新一份快照資料。而在RR級别下,對于快照資料,非一緻性讀總是讀取事務開始時的行資料版本。

一緻性鎖定讀

前面說到,在預設隔離級别RR下,InnoDB存儲引擎的SELECT操作使用一緻性非鎖定讀。但是在某些情況下,使用者需要顯式地對資料庫讀取操作進行加鎖以保證資料邏輯的一緻性。InnoDB存儲引擎對于SELECT語句支援兩種一緻性的鎖定讀(locking read)操作。

SELECT … FOR UPDATE (X鎖)

SELECT … LOCK IN SHARE MODE (S鎖)

3、鎖帶來的問題

通過鎖定機制可以實作事務隔離性要求,使得事務可以并發的工作。鎖提高了并發,但是卻會帶來潛在的問題。

InnoDB存儲引擎在RR級别就已經解決了所有問題,但是它和Serializable的差別在哪裡呢?

差別就在于RR級别還存在一個丢失更新問題,而SERIALIZABLE無論對于查詢還是更新都會進行鎖定操作。

4、死鎖

死鎖是指兩個或兩個以上的事務在執行過程中,因争奪鎖資源而造成的一種互相等待的現象。

繼續閱讀