對於MySQL你必須要了解的鎖知識

2021-09-20 07:39:42 字數 2833 閱讀 4162

mysql 的鎖按照範圍可以分為全域性鎖、表鎖、行鎖,其中行鎖是由資料庫引擎實現的,並不是所有的引擎都提供行鎖,myisam 就不支援行鎖,所以文章介紹行鎖會以innodb引擎為例來介紹行鎖。

mysql 提供全域性鎖來對整個資料庫例項加鎖。

語法:

flush tables with read lock
這條語句一般都是用來備份的,當執行這條語句後,資料庫所有開啟的表都會被關閉,並且使用全域性讀鎖鎖定資料庫的所有表,同時,其他執行緒的更新語句(增刪改),資料定義語句(建表,修改表結構)和更新類的事務提交都會被阻塞。

在mysql 8.0 以後,對於備份,mysql可以直接使用備份鎖。

語句:

lock instance for backup

unlock instance

這個鎖的作用範圍更廣,這個鎖會阻止檔案的建立,重新命名,刪除,包括 repair table truncate table, optimize table操作以及賬戶的管理都會被阻塞。當然這些操作對於記憶體臨時表來說是可以執行的,為什麼記憶體表不受這些限制呢?因為記憶體表不需要備份,所以也就沒必要滿足這些條件。

mysql的表級別鎖分為兩類,一類是元資料鎖(metadata lock,mdl),一種是表鎖。

元資料鎖(mdl) 不需要顯式使用,在訪問乙個表的時候會被自動加上。這個特性需要mysql5.5版本以上才會支援,當對乙個表做增刪改查的時候,該錶會被加mdl讀鎖;當對表做結構變更的時候,加mdl寫鎖。mdl鎖有一些規則:

所以我們在運算元據庫表結構時候必須要注意不要使用長事務,這裡具體是什麼意思呢?我舉個例子說明下:

上圖表示演示了4個session執行語句,首先sessiona開啟了事務沒有提交,接著sessionb執行查詢,因為是獲取mdl讀鎖,所以互相不影響,可以正常執行,sessionc新增乙個字段,由於mdl寫和讀是互斥的,所以sessionc會被阻塞,之後sessiond開始執行乙個查詢語句,由於sessionc的阻塞,所以sessiond也阻塞了。所以,我們模擬的sessiona的事務是長事務,然後後面執行了修改表結構,會導致後續對該錶所有的讀寫操作都不可行了。所以在實際場景中,如果業務請求比較頻繁的時候,對錶結構進行修改的時候就有可能導致該庫的執行緒被阻塞滿。

表鎖 的語法如下:

lock tables

tbl_name [[as] alias] lock_type

[, tbl_name [[as] alias] lock_type] ...

lock_type:

unlock tables

表鎖分為讀鎖和寫鎖,讀鎖不互斥,但是獲取讀鎖不能寫入資料,其他沒有獲取到讀鎖的session也是可以讀取表的,所以讀鎖的目的就是限制表被寫。如果表被讀鎖鎖住後,再執行插入語句會報錯,報錯如下:

1099 - table '***x' was locked with a read lock and can't be updated
寫鎖被獲取後可以對錶進行讀寫,寫鎖是互斥的,一旦某個session獲取到表的寫鎖,另外的session無法訪問這個表,直到寫鎖被釋放。

表的解鎖可以使用unlock tables解鎖,也可以客戶端口自動解鎖。lock tables鎖表會獨佔式的鎖住表,除了限制其他執行緒對該錶的讀寫,也會限制本執行緒接下來的操作物件。

mysql的行鎖是在引擎層面實現的,所以這裡討論的也是innodb引擎下的行鎖,下面會詳細介紹innodb下常見的幾種行鎖

共享鎖能允許事務獲取到鎖後進行讀操作,共享鎖是不互斥的,乙個事務獲取到共享鎖後,另外乙個事務也可以獲取共享鎖,獲取共享鎖後不能進行寫操作。

排他鎖允許事務獲取到鎖後進行更新一行或者刪除某一行操作,排他鎖顧名思義是互斥的,乙個事務獲取到排他鎖後,其他事務不能獲取到排他鎖,直到這個鎖被釋放。

innodb支援多種粒度的鎖,允許行鎖和表鎖共存,這裡說的意向鎖其實是一種表級別的鎖,但是我把它放在行鎖裡面是因為它不會單獨存在,它的出現肯定會伴隨著行鎖(共享鎖或者排他鎖),它主要的目的就是表示將要鎖定表中的行或者正在鎖定表中的行。

意向鎖根據和行鎖的組合可以分為:

意向鎖的獲取必須在行鎖獲取之前,也就是說獲取共享鎖之前必須先要獲取共享意向鎖,對於排他鎖也是一樣的道理。

那麼這個意向鎖到底有什麼作用呢

解釋這個之前,我們先看看意向鎖和行鎖之前的相容關係:

我們假設有2個事務a和事務b,事務獲取到了共享鎖,鎖住了表中的某一行,這一行只能讀,不能寫,現在事務b要申請整個表的寫鎖。如果事務b申請成功,那麼肯定是可以對錶中所有的行進行寫操作的,那麼肯定與a獲取的行鎖衝突。資料庫為了避免這種衝突,就會進行衝突檢測,那麼如何去檢測呢?有兩種方式:

判斷表中的每一行需要遍歷所有記錄,效率太差,所以資料庫就用第一種方式去做衝突檢測,也就是用到了意向鎖。

本文主要從mysql的加鎖範圍來分析了mysql的鎖,mysql根據加鎖範圍可以分為全域性鎖、表鎖、行鎖。全域性鎖和表鎖是mysql自己實現,行鎖都是由引擎層面去實現。innodb下的行鎖主要分為共享鎖和排他鎖。共享鎖請求後,行只能讀,共享鎖之間不互斥。排他鎖獲取後能更新和刪除行,排他鎖與其他鎖都互斥。最後我在行鎖的基礎上提到了意向鎖,意向鎖主要表示正在鎖住行或者即將鎖住行,為了在鎖衝突檢測中提高效率。當然innodb下還有其他鎖,比如間隙鎖,記錄鎖,next-key鎖等,這些都不在本文的**範圍之內,如有興趣的同學可以自行研究。

對於MySQL你必須要了解的鎖知識

mysql 的鎖按照範圍可以分為全域性鎖 表鎖 行鎖,其中行鎖是由資料庫引擎實現的,並不是所有的引擎都提供行鎖,myisam 就不支援行鎖,所以文章介紹行鎖會以innodb引擎為例來介紹行鎖。mysql 提供全域性鎖來對整個資料庫例項加鎖。語法 flush tables with read lock...

對於MySQL你必須要了解的鎖知識

mysql 的鎖按照範圍可以分為全域性鎖 表鎖 行鎖,其中行鎖是由資料庫引擎實現的,並不是所有的引擎都提供行鎖,myisam 就不支援行鎖,所以文章介紹行鎖會以innodb引擎為例來介紹。mysql 提供全域性鎖來對整個資料庫例項加鎖。語法 flush tables with read lock 複...

MySQL必須要了解的鎖知識

mysql 的鎖按照範圍可以分為全域性鎖 表鎖 行鎖,其中行鎖是由資料庫引擎實現的,並不是所有的引擎都提供行鎖,myisam 就不支援行鎖,所以文章介紹行鎖會以innodb引擎為例來介紹。二 全域性鎖 mysql 提供全域性鎖來對整個資料庫例項加鎖。語法 flush tables with read...