1、概述
MySQL 表級(jí)鎖是以單個(gè)表為粒度的鎖,InnoDB 和 MyISAM 引擎都支持表級(jí)鎖;
2、表鎖分類及原理
2.1 表級(jí)共享鎖和表級(jí)排它鎖
加鎖方式:lock tables … read/write;
解鎖方式:可以使用 unlock table; 主動(dòng)解鎖,也可以等客戶端斷開連接時(shí)自動(dòng)釋放;
兼容性:
共享鎖可以兼容其他共享鎖,但不兼容排它鎖,排它鎖則不兼容任何鎖;
注意:
lock tables 語(yǔ)法除了會(huì)限制別的線程的讀寫外,也限定了本線程的操作對(duì)象;
舉例說(shuō)明:如果在某個(gè)線程 A 中執(zhí)行 lock table t1 read, t2 write; 這個(gè)語(yǔ)句,則其他線程寫 t1、讀寫 t2 的語(yǔ)句都會(huì)被阻塞。同時(shí),線程 A 在執(zhí)行 unlock tables 之前,也只能執(zhí)行讀 t1、讀寫 t2 的操作。連寫 t1 都不允許,自然也不能訪問(wèn)其他表;
2.2 意向共享鎖和意向排它鎖
意向鎖是用來(lái)解決表級(jí)鎖和行級(jí)鎖的共存問(wèn)題的,那么它如何做到呢?
例如:事務(wù) A 在表的某一行中加了記錄鎖,事務(wù) B 想在該表上添加表級(jí)排它鎖,這時(shí),事務(wù) B 想要知道是否可以添加表級(jí)排它鎖,就要做全表掃描,看是否有記錄上有記錄鎖,這樣效率極其低下,基本不可用,這時(shí)就需要意向鎖來(lái)解決該問(wèn)題;
有了意向鎖之后,事務(wù) A 在申請(qǐng)記錄鎖之前,數(shù)據(jù)庫(kù)會(huì)自動(dòng)先給事務(wù) A 先申請(qǐng)表的意向排他鎖,當(dāng)事務(wù) B 去申請(qǐng)表級(jí)排它鎖時(shí)就會(huì)失敗,因?yàn)楸砩嫌幸庀蚺潘i之后事務(wù) B 申請(qǐng)表級(jí)排它鎖時(shí)會(huì)被阻塞,這樣事務(wù) B 就避免了全表掃描操作了;
所以,總結(jié)一下意向鎖的作用:
當(dāng)一個(gè)事務(wù)在需要獲取資源的鎖定時(shí),數(shù)據(jù)庫(kù)會(huì)自動(dòng)給該事務(wù)申請(qǐng)一個(gè)該表的意向鎖,如果需要一個(gè)共享鎖定,就申請(qǐng)一個(gè)意向共享鎖,如果需要排他鎖定,則申請(qǐng)一個(gè)意向排他鎖,這樣其他事務(wù)再來(lái)申請(qǐng)資源的時(shí)候,就不用掃描全表來(lái)判斷是否有沖突了;
2.3 自增鎖
自增鎖是一種專門針對(duì) AUTO_INCREMENT 類型的列的鎖,用來(lái)保證自增主鍵的順序和唯一性,有幾種模式可選,通過(guò) innodb_autoinc_lock_mode 參數(shù)來(lái)設(shè)置模式,同一種模式對(duì)于不同的插入類型起到的作用會(huì)不同;
2.3.1 插入類型
Simple Insert(簡(jiǎn)單插入):
插入的記錄數(shù)以及內(nèi)容都確認(rèn),語(yǔ)句包括:insert into values、replace;
Bulk Insert(批量插入):
插入的記錄數(shù)不能馬上確認(rèn),語(yǔ)句包括:INSERT ... SELECT、REPLACE ... SELECT、LOAD DATA;
Mixed-mode Insert(混合插入):
指插入的值中有部分 value 的 id 確認(rèn),另一部分則默認(rèn)自增,如:
- INSERT INTO t1 (c1,c2) VALUES (1,‘a(chǎn)‘), (NULL,‘b‘), (5,‘c‘), (NULL,‘d‘);
- INSERT ... ON DUPLICATE KEY UPDATE;
2.3.2 自增模式
innodb_autoinc_lock_mode = 0
優(yōu)點(diǎn):極其安全;
缺點(diǎn):寫入性能差,任何一種 Insert 語(yǔ)句,都會(huì)產(chǎn)生一個(gè)自增鎖,即:所有的插入語(yǔ)句都串行執(zhí)行;
innodb_autoinc_lock_mode = 1
優(yōu)點(diǎn):非常安全,對(duì)于 “innodb_autoinc_lock_mode = 0”,性能要好很多;
缺點(diǎn):依然會(huì)產(chǎn)生自增鎖;
運(yùn)行原理:
- 當(dāng)發(fā)生 Bulk Inserts 時(shí),會(huì)產(chǎn)生一個(gè)特殊的自增鎖直到語(yǔ)句結(jié)束,注意:(這里是語(yǔ)句結(jié)束就釋放鎖,并不是事務(wù)結(jié)束哦,因?yàn)橐粋€(gè)事務(wù)可能包含很多語(yǔ)句),對(duì)于 Simple Inserts,則使用的是一種輕量級(jí)鎖,只要獲取了相應(yīng)的自增 key 就釋放鎖,并不會(huì)等到語(yǔ)句結(jié)束;
- 當(dāng)有自增鎖時(shí),這種輕量級(jí)的鎖也不會(huì)加鎖成功,會(huì)等待;
思考:這里的自增鎖起到什么作用呢?
他能保證 Bulk Insert 自增 id 的連續(xù)性,防止在 Bulk Insert 的時(shí)候,被其他的插入語(yǔ)句搶走自增值;
innodb_autoinc_lock_mode = 2
優(yōu)點(diǎn):性能最好;
缺點(diǎn):Bulk Insert 時(shí)可能得到不連續(xù)的自增 id,SBR 模式下,會(huì)導(dǎo)致復(fù)制出錯(cuò);
原理:當(dāng)進(jìn)行 Bulk Insert 的時(shí)候,不會(huì)產(chǎn)生自增鎖,因?yàn)樗窃试S其他插入語(yǔ)句同時(shí)進(jìn)行插入,來(lái)一個(gè)記錄,插入分配一個(gè)自增值,不會(huì)預(yù)分配;
2.4 MDL 讀鎖和 MDL 寫鎖
MDL 鎖也叫元數(shù)據(jù)鎖,不需要顯示添加,是在訪問(wèn)表的時(shí)候自動(dòng)添加,若在表上做增刪改查,則添加 MDL 讀鎖,若對(duì)表結(jié)構(gòu)進(jìn)行變更,則添加 MDL 寫鎖;
讀鎖之間不互斥,讀寫鎖、寫鎖之間互斥;
3、總結(jié)
- InnoDB 和 MySIAM 都支持表級(jí)鎖;
- 表級(jí)共享鎖和表級(jí)排它鎖可以主動(dòng)加鎖解鎖,其他表級(jí)鎖都不需要主動(dòng)操作;
- 意向鎖解決了表級(jí)鎖和行級(jí)鎖共存的問(wèn)題;
- 自增鎖有三種模式可選,我們可根據(jù)業(yè)務(wù)需要靈活配置;
- MDL 鎖只在修改表結(jié)構(gòu)的時(shí)候起作用;
4、參考資料
- 表級(jí)共享鎖和表級(jí)排它鎖:極客時(shí)間《MySQL實(shí)戰(zhàn)45講》
- 意向鎖:https://blog.csdn.net/zcl_love_wx/article/details/82015281
- 自增鎖:https://blog.csdn.net/luolaifa000/article/details/81099622
- 自增鎖:http://blog.itpub.net/15498/viewspace-2141640/
- MDL 鎖:極客時(shí)間《MySQL實(shí)戰(zhàn)45講》
5、遺留問(wèn)題
MySQL 的 SBR 模式是什么,如何工作,有什么優(yōu)缺點(diǎn)?