前阿里數據庫專家總結的MySQL裏的各類鎖(上篇)

0.前言

MySQL按照加鎖的範圍,分爲全局鎖、表級鎖、行級鎖。git

本文做爲上篇,主要介紹MySQL的全局鎖 和 表級鎖。github

重要的實戰總結爲,如何安全地變動一個表的表結構。面試

1.全局鎖

定義:數據庫

全局鎖就是對整個數據庫實例加鎖。安全

全局鎖語法:session

Flush tables with read lock (FTWRL)線程

當你使用這個命令後,整個庫處於只讀狀態,以後其餘線程的數據更新語句(DML)、數據定義語句(DDL)都會被阻塞。orm

場景:不支持事務的引擎(如MyISAM),作全庫的邏輯備份。blog

不過咱們通常使用innodb,這個鎖不太會接觸,就不展開詳細介紹了。隊列

2.表級鎖

表級鎖其實有兩種,一種叫表鎖,一種叫原數據鎖(meta data lock, MDL)

2.1 表鎖

表鎖的語法是:

鎖表:lock tables … read/write

釋放鎖: unlock tables 主動釋放鎖

表鎖也可以在客戶端斷開的時候自動釋放。

值得注意的是,lock tables 除了會限制別的線程的讀寫外,當前線程接下來的操做也會被限制。

一樣的,對於innoDB這種支持行鎖的引擎,咱們通常也不會去使用用表鎖,所以,這部份內容也只須要簡單瞭解下便可。

2.2 MDL鎖

原數據鎖meta data lock 也是一種表級鎖,在 MySQL 5.5 版本中引入。

當咱們對一個表作CRUD操做的時候,會加 MDL 讀鎖;當要對錶作結構變動操做的時候,加 MDL 寫鎖。

 

前阿里數據庫專家總結的MySQL裏的各類鎖(上篇)

MDL讀寫鎖的互斥

  • 讀鎖之間不互斥,因此咱們能夠有多個線程同時對一張表增刪改查。
  • 讀鎖和寫鎖之間、寫鎖和寫鎖之間是互斥的,用來保證變動表結構操做的安全性。所以,只要有一個線程要對一個表加字段,那天其餘線程必須等這個線程完成表結構變動之後才能執行。

看到這裏,不得不給你們舉例一個平常會踩的坑。

對於大表DDL,你們通常比較謹慎,而對於小表,就會比較隨意。可是小表DDL也能形成數據庫崩潰。

前阿里數據庫專家總結的MySQL裏的各類鎖(上篇)

Session A第一個啓動,開啓事務,select後沒有馬上commit,模仿一個長事務,此時,session A對錶tt的MDL讀鎖尚未釋放。

Session B以後執行一個select,因爲MDL讀鎖之間不互斥,所以執行成功。

Session C以後想對錶tt 執行一個alter語句,須要得到MDL寫鎖,可是因爲Session A持有了MDL讀鎖,讀寫鎖互斥,所以Session C被阻塞。

Session D這時候也想執行一個select,因爲Session C被阻塞,因此Session D也會被阻塞。

因此這個時候,後續的線程就都沒法讀寫了。

若是接下來這個表上有頻繁的查詢,並且客戶端有重試機制,那麼超時後會再起一個新的session來查詢,很快數據庫的線程就溢出了。

這裏有幾個小問題須要稍微再解釋一下:

1)從Session A的狀況咱們得知,事務中 的MDL鎖,在語句開始時申請,可是並非在語句結束後立刻釋放的,而是在整個事務提交後纔會釋放。

2)SessionC(DDL操做)被前面的SessionA和B(查詢操做,獲取MDL 讀鎖)所阻塞,這裏實際上並無成功獲取MDL寫鎖,爲何Session D的讀操做會被sessionC所阻塞呢?這裏的緣由是,MySQL Server端,對於Session C和Session D會有一個隊列來決定誰先執行。

看到這裏,我相信確定有對MySQL比較熟悉的朋友會問了,MySQL 5.6不是號稱支持Online DDL嗎?怎麼這裏又會有各類阻塞呢?

首先,咱們先明確下什麼叫作Online DDL。

Online DDL的過程當中,對於鎖的獲取分爲五步(具體online DDL過程比較複雜,本文不展開說明):

1)拿到MDL寫鎖

2)降級成MDL讀鎖

3)真正作DDL

4)升級成MDL寫鎖

5)釋放MDL鎖

一、二、四、5若是沒有鎖衝突,執行時間都是很是短的。絕大部分時間是第三步佔用了,而這個期間,表可用正常讀寫,因此被稱爲Online DDL。

而咱們上文的例子,其實是在第一步就阻塞了。

3.So,如何作一次安全的表結構變動

其實,不管大表小表的表結構變動,都應用引發咱們重視。

總結了上文,你們應該都知道了最關鍵的三點:

避免長事務!

避免長事務!

避免長事務!

尤爲是在執行表結構變動前,能夠在information_schema庫的innodb_trx表中,查看當前執行的事務。若是有長事務正在執行,要延遲等待執行變動,或者手動先kill長事務。

另外,儘可能保證表結構變動在數據庫流量低峯期操做,好比夜間,這樣能更好地避免出現風險。

因此,如何作一次安全的表結構變動?

1)避免長事務

2)在流量低峯進行

就是這麼簡單。

 

下一期,咱們就好好聊聊 行鎖,不見不散~

 

參考:

丁奇《MySQL 實戰45講》

 

看到這裏了,原創不易,點個關注、點個贊吧,你最好看了~

知識碎片從新梳理,構建Java知識圖譜:https://github.com/saigu/JavaKnowledgeGraph(歷史文章查閱很是方便)

掃碼關注個人公衆號「阿丸筆記」,第一時間獲取最新更新。同時能夠免費獲取海量Java技術棧電子書、各個大廠面試題。

阿丸筆記

相關文章
相關標籤/搜索