Mysql中的鎖
基於鎖的屬性分類:共享鎖、排他鎖。
基於鎖的狀態分類:意向共享鎖、意向排它鎖
根據鎖的粒度分類:全局鎖、頁鎖、表級鎖、行鎖(記錄鎖、間隙鎖、和臨鍵鎖),實際上的鎖就這些,上面兩種分類只是站在不同維度上看這些鎖
頁級鎖僅被BDB存儲引擎支持,這里不介紹
全局鎖
全局鎖就是對整個數據庫實例加鎖,MySQL提供了一個加全局讀鎖的方法,命令是 Flush tables with read lock (FTWRL)。當你需要讓整個庫處於只讀狀態的時候,可以使用這個命令,之后其他線程的以下語句會被阻塞:數據更新語句(數據的增刪改)、數據定義語句(包括建表、修改表結構等)和更新類事務的提交語句。
表級鎖
表級鎖有兩種:一種是表鎖,一種是元數據鎖(MDL)
開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。數據庫引擎總是一次性同時獲取所有需要的鎖以及總是按相同的順序獲取表鎖從而避免死鎖。
表鎖
表讀鎖 和 表寫鎖
元數據鎖(MDL)
DDL:如果你在session1中select一行數據,這個時候session2給這張表新增了一列xxx,這個時候可能會出現事務特性被破壞、binlog順序錯亂等bug
為了解決DDL,在mysql 5.5版本中引入了MDL
MDL不需要顯式使用,在訪問一個表的時候會自動加上
當對一個表做增刪改查的時候,加MDL讀鎖;
當要對表做結構變更操作的時候,加MDL寫鎖;
- 讀鎖之間不互斥,因此可以有多個線程同時對一張表操作
- 讀寫鎖之間、寫鎖之間互斥的,用來保證變更表結構操作的安全性。
注意:
事務中的MDL鎖,在語句執行開始時申請,但是語句結束並不會馬上釋放,而會等到整個事務提交后在釋放
行鎖
InnoDB和MyISAM有兩個本質的區別:InnoDB支持行鎖、InnoDB支持事務。
特點:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。行鎖總是逐步獲得的,因此會出現死鎖。
行鎖指上鎖的時候鎖住的是表的某一行或多行記錄,其他事務訪問同一張表時,只有被鎖住的記錄不能訪問,其他記錄可正常訪問
InnoDB 實現了標准的行級鎖:
-
共享鎖(讀鎖): 允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖。即多個客戶可以同時讀取同一個資源,但不允許其他客戶修改。
-
排他鎖(寫鎖): 允許獲得排他鎖的事務更新數據,阻止其他事務取得相同數據集的讀鎖和寫鎖。寫鎖是排他的,寫鎖會阻塞其他的寫鎖和讀鎖。
為了允許行鎖和表鎖共存,實現多粒度鎖機制,InnoDB 還有兩種內部使用的意向鎖,這兩種意向鎖都是表鎖:
-
意向共享鎖(IS):事務在給一個數據行加共享鎖前必須先為該表添加意向共享鎖。
-
意向排他鎖(IX):事務打算給數據行加行排他鎖,事務在給一個數據行加排他鎖前必須先為該表添加意向排他鎖。
鎖的算法(對行鎖更精細的划分)
Record Lock(記錄鎖)
只鎖記錄,特定幾行記錄。
它會在遇到的索引記錄上設置共享鎖或排他鎖。因此,記錄鎖可以理解為行鎖的實現
必須是唯一索引 或 主鍵,否則會變成臨建鎖
Gap Lock(間隙鎖)
存在於非唯一索引中
間隙鎖是對索引記錄中的一段連續區域的鎖,鎖住的是一個區間,而不僅僅是這個區間中的每一條數據。
只鎖間隙,前開后開區間(a,b),對索引的間隙加鎖,防止其他事務插入數據。
Next-key Lock(臨鍵鎖)
存在於非唯一索引中
Next-key Lock:記錄鎖+Gap鎖(間歇鎖)
同時鎖住記錄和間隙,前開后閉區間(a,b]。
Next-key鎖的目的是為了解決幻讀的問題
注意點
-
MyISAM和MEMORY存儲引擎采用的是表級鎖,頁級鎖僅被BDB存儲引擎支持,InnoDB存儲引擎支持行級鎖和表級鎖,默認情況下是采用行級鎖。
-
InnoDB行鎖是通過給索引上的索引項加鎖來實現的,Innodb一定存在聚簇索引,行鎖最終都會落到聚簇索引上,通過非聚簇索引查詢的時候,先鎖非聚簇索引,然后再鎖聚簇索引。如果一個where語句里面既有聚簇索引,又有二級索引,則會先鎖聚簇索引,再鎖二級索引。由於是分步加鎖的,因此可能會有死鎖發生。
-
InnoDB 行鎖是通過給索引上的索引項加鎖來實現的,如果沒有索引,會鎖住整個表,注意這里並不是使用表鎖
-
在InnoDB事務中,行鎖是在需要的時候才加上的,但並不是不需要了就立刻釋放,而是等到事務結束才釋放,這就是兩階段鎖協議
-
對於記錄鎖,列必須是唯一索引列或者主鍵列,查詢語句必須為精確匹配,如“=”,否則記錄鎖會退化為臨鍵鎖。
-
間隙鎖和臨鍵鎖基於非唯一索引,在唯一索引列上不存在間隙鎖和臨鍵鎖。
感覺總結的不是很清楚,可以看看大佬的文章
『淺入淺出』MySQL 和 InnoDB - 面向信仰編程 (draveness.me)
你應該了解的MySQL鎖分類 - SegmentFault 思否