鎖介紹#
MySQL 中的鎖,按照鎖的粒度分為以下三類:
- 全局鎖:鎖定資料庫中的所有表
- 表級鎖:每次操作鎖住整張表
- 行級鎖:每次操作鎖住對應的行數據
全局鎖#
全局鎖就是對整個資料庫實例加鎖,加鎖後整個實例就處於只讀狀態,後續 DML 的寫語句,DDL 語句,已經更新操作的事務提交語句都將被阻塞
典型場景是鎖定所有表進行全庫備份,如果不加鎖,就如下圖,可能出現產生了訂單但是庫存沒有扣減的數據不一致
如果加鎖,只能讀不能寫,保證了備份的時刻全局一致
flush tables with read lock; # 加鎖
mysqldump -uroot -p123456 database > database.sql # 備份
unlock tables; # 解鎖
加全局鎖是一個比較重的操作,存在下列弊端
- 如果在主庫上備份,那麼在備份期間都不能執行更新,業務基本上就得停擺
- 如果在從庫上備份,那麼在備份期間從庫不能執行主庫同步過來的二進制日誌 binlog,會導致主從延遲
在 InnoDB 引擎中,加上參數 --single-transaction
可以實現 不加鎖 的一致性數據備份,其底層使用的是快照讀進行備份操作
mysqldump --single-transaction -uroot -p123456 database > database.sql
表級鎖#
表級鎖,每次操作鎖住整張表,鎖定粒度大,發生鎖衝突的概率最高,並發度最低,應用在 MyISAM、InnoDB、BDB 等存儲引擎中
對於表級鎖,主要分為以下三類:
- 表鎖
- 元數據鎖 meta data lock MDL
- 意向鎖
表鎖#
對於表鎖,分為兩類:
- 表共享讀鎖 read lock
- 表獨占寫鎖 write lock
共享讀鎖 read lock,都可以讀,但是都不能寫
獨占寫鎖 write lock,只能上鎖方讀寫,其餘方無法操作
元數據鎖#
meta data lock MDL 加鎖過程由程序自動控制,無需顯式使用,在訪問一張表的時候會自動加上,MDL 鎖主要作用是維護表元數據的數據一致性,在表上有活動事務的時候,不可以對元數據進行寫入操作;為了避免 DML 與 DDL 衝突,保證讀寫的正確性
在 MySQL v5.5 中引入了 MDL:
當對一張表進行增刪改查 DML 的時候,加 MDL 讀鎖 共享
當對表結構進行變更操作 DDL 的時候,加 MDL 寫鎖 排他
元數據鎖大意,事物進行當中,無法修改表結構;
事物進行時的 DML 會申請 MDL 共享讀鎖 SHARE_READ/SHARE_WRITE
修改表結構的 DDL 會申請 MDL 排他鎖 EXCLUSIVE
MDL 主要是針對表結構的 meta data,保證讀取表結構的共享讀鎖 SHARE 和變更表結構的排他寫鎖 EXCLUSIVE,能夠限制增刪改查 DML 時表結構的一致
意向鎖#
為了避免 DML 在執行時,加的行鎖與表鎖的衝突,在 InnoDB 中引入了意向鎖,使得表鎖不用檢查每行數據是否加鎖,使用意向鎖來減少表鎖的檢查
當表中其他事務持有意向共享鎖 IS,此時想給表加 read 表鎖可以,但加 write 表鎖不行,需要等事務釋放意向共享鎖
當表中其他事務持有意向排他鎖 IX,此時想給表加 read 表鎖和 write 表鎖都不行,需要等事務釋放意向排他鎖
行級鎖#
行級鎖,每次操作鎖住對應的行數據,鎖定粒度最小,發生鎖衝突的概率最低,並發度最高,應用在 InnoDB 存儲引擎中
行鎖 Record Lock:鎖定單個行記錄的鎖,防止其他事務對此行進行 update 和 delete,在 ReadCommit、RepeatableRead 隔離級別下都支持
間隙鎖 Gap Lock:鎖定索引記錄間隙 不含該記錄,確保索引記錄間隙不變,防止其他事務在這個間隙進行 insert,產生幻讀,在 RepeatableRead 隔離級別下都支持
臨鍵鎖 Next-Key Lock:行鎖和間隙鎖組合,同時鎖住數據,並鎖住數據前面的間隙 Gap,在 RepeatableRead 隔離級別下支持
行鎖 Record Lock#
兩種行鎖:
- 共享鎖 S:允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖
- 排他鎖 X:允許獲取排他鎖的事務更新數據,阻止其他事務獲得相同數據集的共享鎖和排他鎖
類似於 read/write
相關 SQL 行鎖類型
默認情況下,InnoDB 在 RepeatableRead 事務隔離級別運行,InnoDB 使用臨鍵鎖 next-key lock 進行搜索和索引掃描,以防止幻讀
- 針對唯一索引進行檢索時,對已存在的記錄進行等值匹配時,將會自動優化為行鎖
- InnoDB 的行鎖是針對索引加的鎖,不通過索引條件檢索數據,那麼 InnDB 將對表中的所有記錄加鎖,此時就會 升級為表鎖
間隙鎖 gap lock / 臨鍵鎖 next key lock#
間隙鎖 gap lock 唯一目的是防止其他事務插入間隙,間隙鎖可以共存,一個事務採用的間隙鎖不會阻止另一個事務在同一間隙上採用間隙鎖
有點難理解,借用筆記看看
小結#
- 概述
在並發訪問時,解決數據訪問的一致性、有效性問題
全局鎖、表級鎖、行級鎖 - 全局鎖
對整個資料庫實例加鎖,加鎖後整個實例就處於只讀狀態
性能較差,數據邏輯備份時使用 - 表級鎖
操作鎖住整張表,鎖定粒度大,發生鎖衝突的概率高
表鎖、元數據鎖、意向鎖 - 行級鎖
操作鎖住對應的行數據,鎖定粒度最小,發生鎖衝突的概率最低
行鎖、間隙鎖、臨鍵鎖
此文由 Mix Space 同步更新至 xLog
原始鏈接為 https://blog.0xling.cyou/posts/mysql/mysql-1