Mysql鎖的類型與簡析

數據庫鎖設計的初衷是處理併發問題。做爲多用戶共享的資源,當出現併發訪問的時候,數據庫須要合理地控制資源的訪問規則。而鎖就是用來實現這些訪問規則的重要數據結構。mysql

根據加鎖的範圍,MySQL 裏面的鎖大體能夠分紅全局鎖、表級鎖和行鎖三類。sql

 

全局鎖數據庫

顧名思義,全局鎖就是對整個數據庫實例加鎖。MySQL 提供了一個加全局讀鎖的方法,命令是 Flush tables with read lock (FTWRL)。當你須要讓整個庫處於只讀狀態的時候,可使用這個命令,以後其餘線程的如下語句會被阻塞:數據更新語句(數據的增刪改)、數據定義語句(包括建表、修改表結構等)和更新類事務的提交語句。安全

全局鎖的典型使用場景是,作全庫邏輯備份。也就是把整庫每一個表都 select 出來存成文本。數據結構

官方自帶的邏輯備份工具是 mysqldump。當 mysqldump 使用參數–single-transaction 的時候,導數據以前就會啓動一個事務,來確保拿到一致性視圖。而因爲 MVCC 的支持,這個過程當中數據是能夠正常更新的。併發

你必定在疑惑,有了這個功能,爲何還須要 FTWRL 呢?一致性讀是好,但前提是引擎要支持這個隔離級別。好比,對於 MyISAM 這種不支持事務的引擎,若是備份過程當中有更新,老是隻能取到最新的數據,那麼就破壞了備份的一致性。這時,咱們就須要使用 FTWRL 命令了。工具

因此,single-transaction 方法只適用於全部的表使用事務引擎的庫。若是有的表使用了不支持事務的引擎,那麼備份就只能經過 FTWRL 方法。這每每是 DBA 要求業務開發人員使用 InnoDB 替代 MyISAM 的緣由之一。spa

 

表級鎖線程

MySQL 裏面表級別的鎖有兩種:一種是表鎖,一種是元數據鎖(meta data lock,MDL)。設計

表鎖

表鎖的語法是 lock tables … read/write。與 FTWRL 相似,能夠用 unlock tables 主動釋放鎖,也能夠在客戶端斷開的時候自動釋放。須要注意,lock tables 語法除了會限制別的線程的讀寫外,也限定了本線程接下來的操做對象。

在尚未出現更細粒度的鎖的時候,表鎖是最經常使用的處理併發的方式。而對於 InnoDB 這種支持行鎖的引擎,通常不使用 lock tables 命令來控制併發,畢竟鎖住整個表的影響面仍是太大。

元數據鎖

MDL 不須要顯式使用,在訪問一個表的時候會被自動加上。MDL 的做用是,保證讀寫的正確性。你能夠想象一下,若是一個查詢正在遍歷一個表中的數據,而執行期間另外一個線程對這個表結構作變動,刪了一列,那麼查詢線程拿到的結果跟表結構對不上,確定是不行的。

所以,在 MySQL 5.5 版本中引入了 MDL,當對一個表作增刪改查操做的時候,加 MDL 讀鎖;當要對錶作結構變動操做的時候,加 MDL 寫鎖。

 

  • 讀鎖之間不互斥,所以你能夠有多個線程同時對一張表增刪改查。

  • 讀寫鎖之間、寫鎖之間是互斥的,用來保證變動表結構操做的安全性。所以,若是有兩個線程要同時給一個表加字段,其中一個要等另外一個執行完才能開始執行。

須要注意的是:MDL 會直到事務提交才釋放,在作表結構變動的時候,你必定要當心不要致使鎖住線上查詢和更新。

 

 

行鎖

MySQL 的行鎖是在引擎層由各個引擎本身實現的。但並非全部的引擎都支持行鎖,好比 MyISAM 引擎就不支持行鎖。不支持行鎖意味着併發控制只能使用表鎖,對於這種引擎的表,同一張表上任什麼時候刻只能有一個更新在執行,這就會影響到業務併發度。InnoDB 是支持行鎖的,這也是 MyISAM 被 InnoDB 替代的重要緣由之一。

在 InnoDB 事務中,行鎖是在須要的時候才加上的,但並非不須要了就馬上釋放,而是要等到事務結束時才釋放。這個就是兩階段鎖協議。

知道了這個設定,對咱們使用事務有什麼幫助呢?那就是,若是你的事務中須要鎖多個行,要把最可能形成鎖衝突、最可能影響併發度的鎖儘可能日後放。

舉個例子。

假設你負責實現一個電影票在線交易業務,顧客 A 要在影院 B 購買電影票。咱們簡化一點,這個業務須要涉及到如下操做:

  1. 從顧客 A 帳戶餘額中扣除電影票價;

  2. 給影院 B 的帳戶餘額增長這張電影票價;

  3. 記錄一條交易日誌。

也就是說,要完成這個交易,咱們須要 update 兩條記錄,並 insert 一條記錄。固然,爲了保證交易的原子性,咱們要把這三個操做放在一個事務中。那麼,你會怎樣安排這三個語句在事務中的順序呢?

試想若是同時有另一個顧客 C 要在影院 B 買票,那麼這兩個事務衝突的部分就是語句 2 了。由於它們要更新同一個影院帳戶的餘額,須要修改同一行數據。

根據兩階段鎖協議,不論你怎樣安排語句順序,全部的操做須要的行鎖都是在事務提交的時候才釋放的。因此,若是你把語句 2 安排在最後,好比按照 三、一、2 這樣的順序,那麼影院帳戶餘額這一行的鎖時間就最少。這就最大程度地減小了事務之間的鎖等待,提高了併發度。

死鎖和死鎖檢測

當併發系統中不一樣線程出現循環資源依賴,涉及的線程都在等待別的線程釋放資源時,就會致使這幾個線程都進入無限等待的狀態,稱爲死鎖。

這時候,事務 A 在等待事務 B 釋放 id=2 的行鎖,而事務 B 在等待事務 A 釋放 id=1 的行鎖。 事務 A 和事務 B 在互相等待對方的資源釋放,就是進入了死鎖狀態。當出現死鎖之後,有兩種策略:

  • 一種策略是,直接進入等待,直到超時。這個超時時間能夠經過參數 innodb_lock_wait_timeout 來設置。
  • 另外一種策略是,發起死鎖檢測,發現死鎖後,主動回滾死鎖鏈條中的某一個事務,讓其餘事務得以繼續執行。將參數 innodb_deadlock_detect 設置爲 on,表示開啓這個邏輯。

減小死鎖的主要方向,就是控制訪問相同資源的併發事務量。

相關文章
相關標籤/搜索