MySQL按照加鎖的範圍,分爲全局鎖、表級鎖、行級鎖。面試
本文做爲上篇,主要介紹MySQL的全局鎖 和 表級鎖。數據庫
重要的實戰總結爲,如何安全地變動一個表的表結構。安全
定義:
session
全局鎖就是對整個數據庫實例加鎖。app
全局鎖語法:post
Flush tables with read lock (FTWRL)ui
當你使用這個命令後,整個庫處於只讀狀態,以後其餘線程的數據更新語句(DML)、數據定義語句(DDL)都會被阻塞。spa
場景:不支持事務的引擎(如MyISAM),作全庫的邏輯備份。線程
不過咱們通常使用innodb,這個鎖不太會接觸,就不展開詳細介紹了。orm
表級鎖其實有兩種,一種叫表鎖,一種叫原數據鎖(meta data lock, MDL)
表鎖的語法是:
鎖表:lock tables … read/write
釋放鎖: unlock tables 主動釋放鎖
表鎖也可以在客戶端斷開的時候自動釋放。
值得注意的是,lock tables 除了會限制別的線程的讀寫外,當前線程接下來的操做也會被限制。
一樣的,對於innoDB這種支持行鎖的引擎,咱們通常也不會去使用用表鎖,所以,這部份內容也只須要簡單瞭解下便可。
原數據鎖meta data lock 也是一種表級鎖,在 MySQL 5.5 版本中引入。
當咱們對一個表作CRUD操做的時候,會加 MDL 讀鎖;當要對錶作結構變動操做的時候,加 MDL 寫鎖。
MDL讀寫鎖的互斥
看到這裏,不得不給你們舉例一個平常會踩的坑。
對於大表DDL,你們通常比較謹慎,而對於小表,就會比較隨意。可是小表DDL也能形成數據庫崩潰。
表結構變動阻塞實例
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。
而咱們上文的例子,其實是在第一步就阻塞了。
其實,不管大表小表的表結構變動,都應用引發咱們重視。
總結了上文,你們應該都知道了最關鍵的三點:
避免長事務!
避免長事務!
避免長事務!
尤爲是在執行表結構變動前,能夠在information_schema庫的innodb_trx表中,查看當前執行的事務。若是有長事務正在執行,要延遲等待執行變動,或者手動先kill長事務。
另外,儘可能保證表結構變動在數據庫流量低峯期操做,好比夜間,這樣能更好地避免出現風險。
因此,如何作一次安全的表結構變動?
1)避免長事務
2)在流量低峯進行
就是這麼簡單。
下一期,咱們就好好聊聊 行鎖,不見不散~
參考:
丁奇《MySQL 實戰45講》
【MySQL系列相關】
都看到最後了,原創不易,點個關注,點個贊吧~
掃碼關注個人公衆號「阿丸筆記」,第一時間獲取最新更新。同時能免費獲取海量Java技術棧電子書、各個大廠面試題哦。