鎖是計(jì)算機(jī)協(xié)調(diào)多個(gè)進(jìn)程或線程并發(fā)訪問某一資源的機(jī)制,在數(shù)據(jù)庫中州弟,除傳統(tǒng)的計(jì)算資源(CPU仍律、RAM嘿悬、I/O)爭(zhēng)用外,數(shù)據(jù)也是一種供許多用戶共享的資源水泉。如何保證數(shù)據(jù)并發(fā)訪問的一致性善涨、有效性是所有數(shù)據(jù)庫必須解決的一個(gè)問題,鎖沖突也是影響數(shù)據(jù)庫并發(fā)訪問性能的一個(gè)重要因素草则。
MySQL 中的鎖可以分為以下三類:
- 全局鎖:鎖定數(shù)據(jù)庫中所有的表
- 表級(jí)鎖:每次操作鎖住整張表
- 行級(jí)鎖:每次操作鎖住表中對(duì)應(yīng)的行數(shù)據(jù)
全局鎖
全局鎖就是對(duì)整個(gè)數(shù)據(jù)庫實(shí)例加鎖钢拧,加鎖后整個(gè)實(shí)例處于只讀狀態(tài),后續(xù)的 DML炕横、DDL 語句都會(huì)無法執(zhí)行源内,典型的使用場(chǎng)景就是做全庫的備份,對(duì)所有表進(jìn)行鎖定看锉,從而獲取一致性視圖姿锭,保證數(shù)據(jù)的完整性。
打開全局鎖:
flush tables with read lock;
備份指定數(shù)據(jù)庫伯铣,將 crm 數(shù)據(jù)庫備份到當(dāng)前命令行目錄的 crm.sql 文件中呻此,不是在 MySQL 的命令行中執(zhí)行,可直接在 Windows 命令行執(zhí)行即可腔寡。
mysqldump -u root -p crm > crm.sql
釋放全局鎖:
unlock tables;
在數(shù)據(jù)庫中加全局鎖焚鲜,是一個(gè)比較重的操作,會(huì)存在以下問題:
1、如果在主庫上備份忿磅,那么備份期間都不能執(zhí)行更新操作糯彬,業(yè)務(wù)基本停滯。
2葱她、如果在從庫上備份撩扒,那么備份期間從庫不能執(zhí)行主庫同步過來的二進(jìn)制日志(binlog),導(dǎo)致主從延遲。
在 InnoDB 引擎中吨些,我們可以在備份時(shí)添加參數(shù)--single-transaction
來實(shí)現(xiàn)不加鎖的一致性數(shù)據(jù)備份:
mysqldump --single-transaction -u root -p crm > crm.sql
表級(jí)鎖
每次操作鎖住整張表搓谆,鎖定力度大,發(fā)生鎖沖突的概率高豪墅,并發(fā)度最低泉手。表級(jí)鎖主要分一下幾類:
- 表鎖
- 元數(shù)據(jù)鎖(meta data lock,MDL)
- 意向鎖
表鎖
表鎖可以分為兩類:
1偶器、表共享讀鎖
(read lock)斩萌,當(dāng)前客戶端對(duì)表加鎖后和其它客戶端只能讀表中的數(shù)據(jù),當(dāng)前客戶端對(duì)表的寫操作直接報(bào)錯(cuò)屏轰,其它客戶端的寫操作會(huì)被阻塞颊郎,直到鎖被釋放后才繼續(xù)執(zhí)行。
2霎苗、表獨(dú)占寫鎖
(write lock)袭艺,當(dāng)前客戶端對(duì)表加鎖后其它客戶端對(duì)表的讀寫操作將會(huì)被阻塞,直到鎖被釋放后才會(huì)繼續(xù)執(zhí)行
表鎖的操作語法如下:
-- 加鎖
lock tables 表名... read/write
-- 釋放鎖(直接關(guān)閉客戶端連接也可以釋放鎖)
unlock tables
元數(shù)據(jù)鎖(MDL)
元數(shù)據(jù)可以簡(jiǎn)單的理解為表結(jié)構(gòu)叨粘,元數(shù)據(jù)鎖的加鎖是系統(tǒng)自動(dòng)控制的,無需顯示指定瘤睹,在訪問一張表的時(shí)候會(huì)自動(dòng)加上升敲,該鎖主要作用是維護(hù)表結(jié)構(gòu)數(shù)據(jù)的一致性,在表上有沒提交的事務(wù)時(shí)轰传,對(duì)表結(jié)構(gòu)的更新操作會(huì)處于阻塞狀態(tài)驴党。
MySQL5.5 開始引入了 MDL,在對(duì)一張表進(jìn)行增刪改查的時(shí)候获茬,會(huì)自動(dòng)加上 MDL 讀鎖(共享鎖)港庄;在對(duì)表結(jié)構(gòu)進(jìn)行變更操作時(shí),會(huì)加上 MDL 寫鎖(排它鎖)恕曲。
意向鎖
當(dāng)對(duì)表中數(shù)據(jù)執(zhí)行 DML 時(shí)會(huì)鎖定行數(shù)據(jù)鹏氧,此時(shí)如果其它客戶端要對(duì)表加表鎖,則需要檢查表中每一行數(shù)據(jù)是否加鎖了佩谣。為了避免在執(zhí)行 DML 語句的時(shí)候把还,加的行鎖與表鎖沖突,在 InnoDB 中引入了意向鎖,使得表鎖不用檢查每行數(shù)據(jù)是否加鎖吊履,減少了表鎖的檢查安皱,提高了效率。
有了意向鎖后艇炎,在執(zhí)行 DML 時(shí)酌伊,先添加行數(shù)據(jù)鎖,然后對(duì)整張表添加意向鎖缀踪,其它客戶端在添加表鎖時(shí)先檢查意向鎖居砖,如果意向鎖和要添加的表鎖是兼容的則添加成功,否則添加表鎖的操作會(huì)被阻塞辜贵。
意向鎖可以分為以下兩類:
1悯蝉、意向共享鎖(IS),由語句 select ... lock in share mode 添加托慨,與表鎖中的表共享讀鎖兼容鼻由,與表獨(dú)占寫鎖互斥。
2厚棵、意向排它鎖(IX)蕉世,由語句 insert、update婆硬、delete狠轻、select ... for update 添加,與表鎖中的表共享讀鎖彬犯、表獨(dú)占寫鎖都互斥向楼。意向鎖之間不會(huì)互斥。
行級(jí)鎖
每次操作鎖住對(duì)應(yīng)的數(shù)據(jù)行谐区,鎖定粒度最小湖蜕,發(fā)生沖突的概率最低,并發(fā)程度高宋列,主要用在 InnoDB 存儲(chǔ)引擎中昭抒。InnoDB 的數(shù)據(jù)是基于索引組織的,行鎖是通過對(duì)索引上的索引項(xiàng)加鎖來實(shí)現(xiàn)的炼杖,而不是對(duì)記錄加鎖的灭返。
行級(jí)鎖主要分為以下幾類:
1、行鎖(Record Lock):鎖定單個(gè)行記錄的鎖坤邪,防止其他事務(wù)對(duì)其進(jìn)行 update熙含、delete,在
read committed艇纺、repeatable read 兩種隔離級(jí)別下都支持婆芦。
2怕磨、間隙鎖(Gap Lock):鎖定索引記錄左右的間隙(不含該記錄),確保索引記錄間隙不變消约,防止其他事務(wù)在這個(gè)間隙進(jìn)行 insert 產(chǎn)生幻讀肠鲫,在 repeatable read 隔離級(jí)別下支持。
3或粮、臨鍵鎖(Next-Key Lock):行鎖和間隙鎖的組合导饲,同時(shí)鎖住數(shù)據(jù)和數(shù)據(jù)前面的間隙,在 repeatable read 隔離級(jí)別下支持氯材。
行鎖
在 InnoDB 中實(shí)現(xiàn)了兩類行鎖:
1渣锦、共享鎖(s):允許獲得共享鎖的事務(wù)讀取一行數(shù)據(jù),允許其他事務(wù)獲得相同數(shù)據(jù)集的共享鎖氢哮,但阻止獲得排它鎖袋毙。共享鎖和排它鎖是互斥的。
2冗尤、排它鎖(x):允許獲取排它鎖的事務(wù)更新一行數(shù)據(jù)听盖,阻止其它事務(wù)獲得相同數(shù)據(jù)集的共享鎖和排它鎖。排它鎖和其它鎖都是互斥的裂七。
常見 SQL 操作對(duì)應(yīng)的行鎖類型:
SQL | 行鎖類型 | 說明 |
---|---|---|
insert | 排它鎖 | 自動(dòng)加鎖 |
update | 排它鎖 | 自動(dòng)加鎖 |
delete | 排它鎖 | 自動(dòng)加鎖 |
select | 不加鎖 | |
select ... lock in share mode | 共享鎖 | 需要手動(dòng)在 select 后添加 lock in share mode |
select ... for update | 排它鎖 | 需要手動(dòng)在 select 后添加 for update |
默認(rèn)情況下皆看,InnoDB 在 repeatable read 事務(wù)隔離級(jí)別下運(yùn)行,并使用臨鍵鎖進(jìn)行搜索和索引掃描來防止幻讀背零。
1腰吟、針對(duì)唯一索引進(jìn)行檢索時(shí),對(duì)已存在的記錄進(jìn)行等值匹配時(shí)徙瓶, 臨鍵鎖會(huì)自動(dòng)優(yōu)化為行鎖毛雇。
2、InnoDB 的行鎖是針對(duì)索引加的鎖侦镇,如果不通過索引字段檢索數(shù)據(jù)禾乘,那么 InnoDB 會(huì)將表中的所有記錄加鎖,此時(shí)會(huì)升級(jí)為表鎖虽缕,影響效率。
可以通過以下 SQL 查看意向鎖以及行鎖的加鎖情況:
select object_schema, object_name, index_name, lock_type, lock_mode, lock_data from performance_schema.data_locks;
間隙鎖蒲稳、臨鍵鎖
間隙鎖唯一的目是防止其它事務(wù)插入間隙氮趋,間隙鎖可以共存,一個(gè)事務(wù)采用的間隙鎖不會(huì)阻止另一個(gè)事務(wù)在同一間隙上采用間隙鎖江耀。
默認(rèn)情況下剩胁,InnoDB 在 repeatable read 事務(wù)隔離級(jí)別下運(yùn)行,并使用臨鍵鎖鎖進(jìn)行搜索和索引掃描來防止幻讀祥国。
1昵观、索引上的等值查詢(唯一索引)晾腔,給不存在的記錄加鎖時(shí),臨鍵鎖優(yōu)化為間隙鎖啊犬。
2灼擂、索引上的等值查詢(普通索引),向右遍歷時(shí)最后一個(gè)值不滿足查詢條件時(shí)觉至,臨鍵鎖退化為間隙鎖剔应。
3、索引上的范圍查詢(唯一索引)语御,會(huì)訪問到不滿足條件的第一個(gè)值為止峻贮。