MySQL鎖概述
相對其他資料庫而言,MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支援不同的鎖機制。比如,MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking);BDB存儲引擎采用的是頁面鎖(page-level locking),但也支援表級鎖;InnoDB存儲引擎既支援行級鎖(row-level locking),也支援表級鎖,但預設情況下是采用行級鎖。
MySQL這3種鎖的特性可大緻歸納如下。
開銷、加鎖速度、死鎖、粒度、并發性能
l 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的機率最高,并發度最低。
l 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的機率最低,并發度也最高。
l 頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般。
僅從鎖的角度來說:表級鎖更适合于以查詢為主,隻有少量按索引條件更新資料的應用,如Web應用;而行級鎖則更适合于有大量按索引條件并發更新少量不同資料,同時又有并發查詢的應用,如一些線上事務處理(OLTP)系統。
MyISAM表鎖(偏讀)
MyISAM存儲引擎隻支援表鎖
查詢表級鎖争用情況

Table_locks_immediate:産生表級鎖定的次數,表示可以立即擷取鎖的查詢次數,每立即擷取鎖值加1
Table_locks_waited:出現表級鎖定争用而發生等待的次數(不能立即擷取鎖的次數,沒等待一次鎖值加1)。此值比較高則說明存在着較嚴重的表級鎖争用情況
MySQL的表級鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨占寫鎖(Table Write Lock)。鎖模式的相容性如下表:
相容性 | None(請求鎖模式) | 讀鎖(請求鎖模式) | 寫鎖(請求鎖模式) |
---|---|---|---|
讀鎖(目前鎖模式) | 是 | 是 | 否 |
寫鎖(目前鎖模式) | 是 | 否 | 否 |
可見:
對MyISAM表的讀操作,不會阻塞其他使用者對同一表的讀請求,但會阻塞對同一表的寫請求;
對 MyISAM表的寫操作,則會阻塞其他使用者對同一表的讀和寫操作;
MyISAM表的讀操作與寫操作之間,以及寫操作之間是串行的。當一個線程獲得對一個表的寫鎖後,隻有持有鎖的線程可以對表進行更新操作。其他線程的讀、寫操作都會等待,直到鎖被釋放為止。
InnoDB表鎖(偏寫)
InnoDB行鎖是通過給索引上的索引項加鎖來實作的,InnoDB這種行鎖實作特點意味着:隻有通過索引條件檢索資料,InnoDB才使用行級鎖,否則,InnoDB将使用表鎖!
擷取InnoDB行鎖争用情況
對各狀态量的說明如下:
示例
通過非索引條件檢索資料,InnoDB使用表級鎖例子
session1 | session2 |
---|---|
| |
| - |
- | |
| - |
- | |
通過索引條件檢索資料,InnoDB使用行級鎖例子
session1 | session2 |
---|---|
| |
| - |
- | |
索引失效 行鎖變表鎖
session1 | session2 |
---|---|
| - |
- | |
間隙鎖
間隙鎖(Gap Lock):鎖加在不存在的空閑空間,可以是兩個索引記錄之間,也可能是第一個索引記錄之前或最後一個索引之後的空間。
間隙鎖是innodb中行鎖的一種,但是這種鎖鎖住的卻不止一行資料,他鎖住的是多行,是一個資料範圍。間隙鎖的主要作用是為了防止出現幻讀,但是它會把鎖定範圍擴大,在某些場景下這可能會對性能造成很大的危害。
示例:如果一個間隙被事務T1加了鎖,其它事務是不能在這個間隙插入記錄的。
session1 | session2 |
---|---|
| - |
- | |
| |
間隙鎖的目的是為了防止幻讀,其主要通過兩個方面實作這個目的:
(1)防止間隙内有新資料被插入
(2)防止已存在的資料,更新成間隙内的資料(例如防止numer=3的記錄通過update變成number=5)
innodb自動使用間隙鎖的條件:
(1)必須在RR級别下
(2)檢索條件必須有索引(沒有索引的話,mysql會全表掃描,那樣會鎖定整張表所有的記錄,包括不存在的記錄,此時其他事務不能修改不能删除不能添加)
如何鎖定一行
FOR UPDATE僅适用于InnoDB,且必須在交易區塊(BEGIN/COMMIT)中才能生效。
假設有個表單products ,裡面有id跟name二個欄位,id是主鍵。
例1: (明确指定主鍵,并且有此記錄,row lock)
SELECT * FROM products WHERE id=’3’ FOR UPDATE;
SELECT * FROM products WHERE id=’3’ and type=1 FOR UPDATE;
例2: (明确指定主鍵,若查無此記錄,無lock)
SELECT * FROM products WHERE id=’-1’ FOR UPDATE;
例2: (無主鍵,table lock)
SELECT * FROM products WHERE name=’Mouse’ FOR UPDATE;
例3: (主鍵不明确,table lock)
SELECT * FROM products WHERE id<>’3’ FOR UPDATE;
例4: (主鍵不明确,table lock)
SELECT * FROM products WHERE id LIKE ‘3’ FOR UPDATE;