MySQL 全局鎖、表級鎖、行級鎖,你搞清楚了嗎?

大家好,我是小林 。
最近重新補充了《MySQL 有哪些鎖》文章內容:

  • 增加記錄鎖、間隙鎖、net-key 鎖
  • 增加插入意向鎖
  • 增加自增鎖為 innodb_autoinc_lock_mode = 2 模式時,為什么主從環境會有不安全問題的說明
所以,現在內容還是比較全面的,基本把 MySQL 用到的鎖都說了一遍,大家可以在復習復習 。
這次 , 來說說 MySQL 的鎖,主要是 Q&A 的形式,看起來會比較輕松 。
不多 BB 了 , 發車!
在 MySQL 里,根據加鎖的范圍 , 可以分為全局鎖、表級鎖和行鎖三類 。
MySQL 全局鎖、表級鎖、行級鎖,你搞清楚了嗎?

文章插圖
全局鎖
全局鎖是怎么用的?
要使用全局鎖 , 則要執行這條命:
flush tables with read lock執行后 , 整個數據庫就處于只讀狀態了,這時其他線程執行以下操作,都會被阻塞:
  • 對數據的增刪改操作,比如 insert、delete、update等語句;
  • 對表結構的更改操作,比如 alter table、drop table 等語句 。
如果要釋放全局鎖 , 則要執行這條命令:
unlock tables當然,當會話斷開了,全局鎖會被自動釋放 。
全局鎖應用場景是什么?
全局鎖主要應用于做全庫邏輯備份,這樣在備份數據庫期間,不會因為數據或表結構的更新 , 而出現備份文件的數據與預期的不一樣 。
舉個例子大家就知道了 。
在全庫邏輯備份期間,假設不加全局鎖的場景 , 看看會出現什么意外的情況 。
如果在全庫邏輯備份期間,有用戶購買了一件商品,一般購買商品的業務邏輯是會涉及到多張數據庫表的更新 , 比如在用戶表更新該用戶的余額 , 然后在商品表更新被購買的商品的庫存 。
那么,有可能出現這樣的順序:
  1. 先備份了用戶表的數據;
  2. 然后有用戶發起了購買商品的操作;
  3. 接著再備份商品表的數據 。
也就是在備份用戶表和商品表之間 , 有用戶購買了商品 。
這種情況下,備份的結果是用戶表中該用戶的余額并沒有扣除,反而商品表中該商品的庫存被減少了,如果后面用這個備份文件恢復數據庫數據的話,用戶錢沒少 , 而庫存少了,等于用戶白嫖了一件商品 。
所以,在全庫邏輯備份期間,加上全局鎖,就不會出現上面這種情況了 。
加全局鎖又會帶來什么缺點呢?
加上全局鎖,意味著整個數據庫都是只讀狀態 。
那么如果數據庫里有很多數據,備份就會花費很多的時間,關鍵是備份期間 , 業務只能讀數據 , 而不能更新數據,這樣會造成業務停滯 。
既然備份數據庫數據的時候 , 使用全局鎖會影響業務,那有什么其他方式可以避免?
有的 , 如果數據庫的引擎支持的事務支持可重復讀的隔離級別,那么在備份數據庫之前先開啟事務,會先創建 Read View,然后整個事務執行期間都在用這個 Read View,而且由于 MVCC 的支持 , 備份期間業務依然可以對數據進行更新操作 。
因為在可重復讀的隔離級別下,即使其他事務更新了表的數據 , 也不會影響備份數據庫時的 Read View,這就是事務四大特性中的隔離性,這樣備份期間備份的數據一直是在開啟事務時的數據 。
備份數據庫的工具是 mysqldump,在使用 mysqldump 時加上 –single-transaction 參數的時候 , 就會在備份數據庫之前先開啟事務 。這種方法只適用于支持「可重復讀隔離級別的事務」的存儲引擎 。
InnoDB 存儲引擎默認的事務隔離級別正是可重復讀,因此可以采用這種方式來備份數據庫 。
但是,對于 MyISAM 這種不支持事務的引擎,在備份數據庫時就要使用全局鎖的方法 。
表級鎖
MySQL 表級鎖有哪些?具體怎么用的 。
MySQL 里面表級別的鎖有這幾種:
  • 表鎖;
  • 元數據鎖(MDL);
  • 意向鎖;
  • AUTO-INC 鎖;
表鎖先來說說表鎖 。
如果我們想對學生表(t_student)加表鎖 , 可以使用下面的命令:
//表級別的共享鎖 , 也就是讀鎖;lock tables t_student read;//表級別的獨占鎖 , 也就是寫鎖;lock tables t_stuent write;

推薦閱讀