MySQL 的鎖機制是其並發控制的核心,不同存儲引擎支援不同的鎖粒度,這直接影響資料庫的效能與並發能力。理解鎖的類型、特性及適用場景,對於優化資料庫效能、避免死鎖至關重要。
支援引擎:MyISAM、MEMORY
特性:鎖定整張資料表。讀鎖(共享鎖)允許並發讀取,但阻塞寫入;寫鎖(排他鎖)阻塞所有其他讀寫操作。開銷小、加鎖快、不會產生死鎖,但鎖定粒度大,衝突機率最高,並發度最低。
適用場景:以查詢為主、少量按索引條件更新資料的應用(如 Web 應用)。
支援引擎:InnoDB
特性:僅鎖定指定記錄,其他進程仍可操作同表中其他記錄。開銷大、加鎖慢、可能出現死鎖,但鎖定粒度最小,衝突機率最低,並發度最高。
優點:
缺點:
適用場景:大量按索引條件並發更新少量不同資料,同時有並發查詢的 OLTP 系統。
支援引擎:BDB
特性:一次鎖定相鄰的一組記錄,開銷與加鎖時間介於表鎖與行鎖之間,會出現死鎖,並發度一般。屬於折衷方案。
InnoDB 與 BDB 在 SQL 處理期間自動獲得鎖(行鎖/頁鎖),而非事務啟動時獲得,因此可能發生死鎖。MyISAM 表級鎖透過鎖隊列管理:寫鎖請求優先於讀鎖請求,可能導致大量寫操作造成查詢永久阻塞,可透過 low_priority_updates=1 調整優先級。
InnoDB 透過索引項加鎖實現行鎖,只有透過索引條件檢索資料才使用行級鎖,否則退化為表鎖。兩種行鎖模式:
SELECT ... LOCK IN SHARE MODE,允許讀取,阻塞其他事務獲取排他鎖SELECT ... FOR UPDATE,允許更新,阻塞其他事務獲取共享鎖與排他鎖為支援多粒度鎖,InnoDB 還引入意向共享鎖 (IS) 與意向排他鎖 (IX),均為表級鎖。
-- 例1:明確指定主鍵且存在記錄 → Row Lock
SELECT * FROM products WHERE id='3' FOR UPDATE;
-- 例2:明確指定主鍵但查無記錄 → 無鎖
SELECT * FROM products WHERE id='-1' FOR UPDATE;
-- 例3:無主鍵條件 → Table Lock
SELECT * FROM products WHERE name='Mouse' FOR UPDATE;
-- 例4:主鍵不明確(不等於) → Table Lock
SELECT * FROM products WHERE id<>'3' FOR UPDATE;
-- 例5:主鍵不明確(LIKE) → Table Lock
SELECT * FROM products WHERE id LIKE '3' FOR UPDATE;
注意: FOR UPDATE 僅適用於 InnoDB,且必須在事務區塊 (BEGIN/COMMIT) 中生效。
| 參數 | 說明 | 適用引擎 |
|---|---|---|
bulk_insert_buffer_size | 批量插入緩存大小,適用 100-1000+ 條記錄一次性插入,預設 8M | MyISAM |
concurrent_insert | 並發插入控制:0=不允許,1=無空洞時允許(預設),2=無論是否有空洞皆允許 | MyISAM |
delay_key_write | 延遲更新索引:更新資料先寫磁盤,索引留內存,表關閉時寫入磁盤。預設開啟 | MyISAM |
delayed_insert_* | 延遲插入相關參數,將資料先交給內存隊列慢慢插入 | MyISAM(InnoDB 不支援) |
從鎖的角度選擇存儲引擎:
正確理解鎖機制,結合索引設計與 SQL 優化,才能充分發揮 MySQL 的並發效能。