seo網(wǎng)站做推廣的公司輔導(dǎo)班培訓(xùn)機(jī)構(gòu)
1.什么是鎖
鎖是計(jì)算機(jī)協(xié)調(diào)多個(gè)進(jìn)程或線程并發(fā)訪問(wèn)某一資源的機(jī)制。
在數(shù)據(jù)庫(kù)中,數(shù)據(jù)是供許多用戶共享的資源,數(shù)據(jù)庫(kù)必須保證數(shù)據(jù)并發(fā)訪問(wèn)的一致性、有效性,這就要靠鎖來(lái)協(xié)調(diào)實(shí)現(xiàn)。
MySOL中的鎖,分為以下三類:
(1)全局鎖:鎖定數(shù)據(jù)庫(kù)中的所有表
(2)表級(jí)鎖:每次操作鎖住整張表
(3)行級(jí)鎖:每次操作鎖住對(duì)應(yīng)的行數(shù)據(jù)
2.全局鎖
2.1全局鎖的作用
全局鎖就是對(duì)整個(gè)數(shù)據(jù)庫(kù)實(shí)例加鎖,加鎖后整個(gè)實(shí)例就處于只讀狀態(tài)(DML、DDL不可執(zhí)行,DQL可執(zhí)行)已經(jīng)更新操作的事務(wù)提交語(yǔ)句都將被阻塞。
其典型的使用場(chǎng)景是做全庫(kù)的邏輯備份,對(duì)所有的表進(jìn)行鎖定,保證數(shù)據(jù)的完整性、一致性。
數(shù)據(jù)庫(kù)的備份是逐表進(jìn)行的,可能剛剛完成了A表的備份,與A表相關(guān)的B表又更新了數(shù)據(jù),造成了數(shù)據(jù)的不一致,因此備份前要加上全局鎖
2.2實(shí)例備份
2.2.1使用全局鎖的方法
(1)先進(jìn)入數(shù)據(jù)庫(kù),通過(guò)以下命令創(chuàng)建全局鎖:
flush tables with read lock;
(2)創(chuàng)建全局鎖后,退出數(shù)據(jù)庫(kù),在windows或linux的命令行界面使用以下命令進(jìn)行備份:
mysqldump -u登錄數(shù)據(jù)庫(kù)的用戶?-p密碼 數(shù)據(jù)庫(kù)名>文件名
#-u與-p和后面的內(nèi)容之間是沒(méi)有空格的
#命令中的文件名,指的就是數(shù)據(jù)被復(fù)制后,存儲(chǔ)到了這個(gè)文件里
#如果操作的不是本地?cái)?shù)據(jù)庫(kù),而是遠(yuǎn)程連接的,那么就需要在命令里加上 -h 遠(yuǎn)程數(shù)據(jù)庫(kù)ip
(3)備份完成后,再進(jìn)入數(shù)據(jù)庫(kù),輸入以下命令解開(kāi)全局鎖:
unlock tables;
2.2.2不使用全局鎖的方法
由于數(shù)據(jù)庫(kù)中加全局鎖是一個(gè)比較重的操作,且存在以下問(wèn)題:
(1)如果在主庫(kù)上備份,那么在備份期間都不能執(zhí)行更新,業(yè)務(wù)基本上就得停擺。
(2)如果在從庫(kù)上備份,那么在備份期間從庫(kù)不能執(zhí)行主庫(kù)同步過(guò)來(lái)的二進(jìn)制日志(binlog),會(huì)導(dǎo)致主從延遲
因此實(shí)際生產(chǎn)中要慎用全局鎖。
在InnoDB引擎環(huán)境下,還有一種不使用全局鎖實(shí)現(xiàn)一致性備份數(shù)據(jù)庫(kù)的方法,只需在mysqldump命令里添加一個(gè)參數(shù)即可:
mysqldump --single-transaction -u登錄數(shù)據(jù)庫(kù)的用戶?-p密碼 數(shù)據(jù)庫(kù)名>文件名
#注意--single-transaction沒(méi)有空格
3.表級(jí)鎖
表級(jí)鎖,每次操作鎖住整張表。鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。應(yīng)用在MyISAM、InnoDB、BDB等存儲(chǔ)引擎中。
對(duì)于表級(jí)鎖,主要分為以下三類:
(1)表鎖
(2)元數(shù)據(jù)鎖(meta data lock,MDL)
(3)意向鎖
3.1表鎖
表鎖分為兩類:
(1)表共享讀鎖,簡(jiǎn)稱讀鎖
(2)表獨(dú)占寫鎖,簡(jiǎn)稱寫鎖
執(zhí)行鎖操作的會(huì)話 | 其他會(huì)話 | |
讀鎖 | 只可讀(只能DQL,不能DML、DDL) | 只可讀(只能DQL,不能DML、DDL) |
寫鎖 | 可讀可寫(DQL、DML、DDL都可以) | 不可讀不可寫(DQL、DML、DDL都不可以) |
語(yǔ)法:
lock tables 表名 read或write;
#加鎖
unlock tables;
#解鎖,這條命令會(huì)解鎖當(dāng)前會(huì)話下的所有表鎖
表鎖是以會(huì)話為分界的,而不是以客戶端為分界的,也不是以mysql用戶為分界的。也就是說(shuō),在當(dāng)前會(huì)話加了寫鎖,其他會(huì)話就無(wú)法讀寫(哪怕是同一客戶端同一mysql用戶)
3.2元數(shù)據(jù)鎖
*元數(shù)據(jù)鎖(MDL)是系統(tǒng)自動(dòng)添加的,無(wú)需手動(dòng)使用
*元數(shù)據(jù)鎖是用來(lái)防止DML與DDL起沖突的
要明白元數(shù)據(jù)鎖的作用,需要先回顧一下事務(wù)的4個(gè)隔離級(jí)別,其中mysql默認(rèn)隔離級(jí)別Repeatable Read正是靠元數(shù)據(jù)鎖來(lái)實(shí)現(xiàn)的
元數(shù)據(jù)鎖也有共享讀鎖與獨(dú)占寫鎖,二者相互排斥:
(1)當(dāng)在一個(gè)事務(wù)中對(duì)某個(gè)表進(jìn)行增刪改查(DQL、DML)時(shí),系統(tǒng)會(huì)自動(dòng)給這個(gè)表加上共享讀鎖。其他事務(wù)可以對(duì)這個(gè)表進(jìn)行增刪改查,但不能修改表結(jié)構(gòu)(DDL)
(2)當(dāng)在一個(gè)事務(wù)中對(duì)某個(gè)表進(jìn)行了修改表結(jié)構(gòu),即DDL操作(alter table ...),那么系統(tǒng)就會(huì)自動(dòng)給這個(gè)表加上獨(dú)占寫鎖,其他事務(wù)既不可對(duì)該表進(jìn)行增刪改查(DQL、DML),也不可修改表結(jié)構(gòu)(DDL)
事務(wù)提交后,元數(shù)據(jù)鎖會(huì)自動(dòng)解開(kāi)
3.3意向鎖
對(duì)表進(jìn)行DML操作時(shí),系統(tǒng)會(huì)暫時(shí)給被操作的數(shù)據(jù)行加上行鎖,如果這時(shí)還要給該表加上表鎖,就會(huì)造成行鎖與表鎖的沖突(即DML自動(dòng)添加的行鎖與表鎖的沖突),為了解決這個(gè)沖突的問(wèn)題,就需要使用意向鎖。
簡(jiǎn)單來(lái)說(shuō),意向鎖是在進(jìn)行DML操作時(shí)與行鎖一起添加的,有了意向鎖后,再要添加表鎖,系統(tǒng)就會(huì)先判斷表鎖與所添加的意向鎖是否兼容,如果兼容則可以加表鎖,否則就不可。
意向鎖有2種:
(1)意向共享鎖(IS)
可由以下語(yǔ)句添加:
select... lock in share mode
IS與讀鎖(read)兼容,與寫鎖(write)互斥,也就是說(shuō),添加了IS后,可以對(duì)表加讀鎖,但不能加寫鎖
(2)意向排他鎖(IX)
insert語(yǔ)句、update語(yǔ)句、delete語(yǔ)句會(huì)自動(dòng)添加意向排他鎖,select語(yǔ)句可由以下語(yǔ)句添加:
select...for update
IX與讀鎖、寫鎖都互斥
3.4三種表級(jí)鎖總結(jié)
是否是系統(tǒng)自動(dòng)添加 | 對(duì)表的作用 | 一句話總結(jié)有啥用 | ||
元數(shù)據(jù)鎖 | 是 | 我對(duì)這張表進(jìn)行增刪改查時(shí),你也可以進(jìn)行增刪改查,但你不能更改表結(jié)構(gòu)(DDL) | 解決DDL與DML的沖突 | |
表鎖 | 讀鎖(read) | 否 | 我不能對(duì)表增刪改(DML),只能查(DQL)。 你也一樣。 | 就鎖表用的,你用你就加,不用就不加 |
寫鎖 (write) | 否 | 我可以對(duì)表增刪改查。 你都不可以 | ||
意向鎖 | 意向共享鎖(IS) | 否 | 表可以加read,不能加write | 解決DML自動(dòng)添加的行鎖與表鎖的沖突 |
意向排他鎖(IX) | 執(zhí)行增刪改時(shí)是自動(dòng),執(zhí)行查時(shí)需手動(dòng)添加 | 表read、write都不能加 |
4.行級(jí)鎖
*行級(jí)鎖:每次操作鎖住對(duì)應(yīng)的行數(shù)據(jù)。鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度最高。
*應(yīng)用在InnoDB存儲(chǔ)引擎中。
*由于InnoDB的數(shù)據(jù)是基于索引組織的,行鎖是通過(guò)對(duì)索引上的索引項(xiàng)加鎖來(lái)實(shí)現(xiàn)的,而不是對(duì)記錄加的鎖。
對(duì)于行級(jí)鎖,主要分為以下三類:
(1)行鎖(Record Lock):鎖定單個(gè)行記錄的鎖,防止其他事務(wù)對(duì)此行進(jìn)行update和delete。在RC、RR事務(wù)隔離級(jí)別下都支持
(2)間隙鎖(Gap Lock):鎖定索引記錄間隙(不含該記錄),確保索引記錄間隙不變,防止其他事務(wù)在這個(gè)間隙進(jìn)行insert,產(chǎn)生幻讀。在RR事務(wù)隔離級(jí)別下支持。
(3)臨鍵鎖(Next-key Lock):行鎖+間隙鎖。在RR事務(wù)隔離級(jí)別下支持。
4.1行鎖
4.1.1共享鎖與排他鎖
InnoDB實(shí)現(xiàn)了以下2種行鎖
(1)共享鎖(S):其他事務(wù)可以和當(dāng)前事務(wù)一起讀一行帶有S的數(shù)據(jù)。共享鎖之間可兼容,但與排他鎖互斥。
(2)排他鎖(X):若某行數(shù)據(jù)被加上了排他鎖,那么就只有當(dāng)前事務(wù)能操作它,其他事務(wù)不能刪改,也不能查。排他鎖之間也是互斥的
4.1.2加鎖以及查看鎖
可以看到行鎖的加鎖情況與意向共享鎖相同,也就說(shuō)明二者會(huì)同時(shí)添加。
不要忘了意向共享鎖是為了解決行鎖與表鎖的沖突才設(shè)置的,因此二者才會(huì)同時(shí)添加?
*通過(guò)下圖語(yǔ)句可以查看系統(tǒng)內(nèi)的鎖,其中IS是意向共享鎖,
S,REC_NOT_GAP是共享鎖,S,GAP是間隙鎖,S是臨鍵鎖
4.1.3行鎖自動(dòng)升級(jí)為表鎖的情況
InnoDB行鎖是針對(duì)索引的鎖,如果對(duì)沒(méi)有索引的字段加行鎖,那么行鎖就會(huì)自動(dòng)升級(jí)為表鎖
比如在事務(wù)A中修改a字段的數(shù)據(jù)(update),同時(shí)a字段沒(méi)有索引,那么由于update操作自動(dòng)給這行數(shù)據(jù)添加了排他鎖,同時(shí)由于a字段沒(méi)有索引,這個(gè)排他鎖自動(dòng)升級(jí)為表鎖,這個(gè)表的每一行數(shù)據(jù)就都要收到排他鎖的限制,事務(wù)B不能對(duì)這個(gè)表進(jìn)行增刪改查
4.2間隙鎖與臨鍵鎖
RR隔離級(jí)別下不同索引在不同查詢情況下的加鎖類型:
非唯一索引 | 范圍查詢 | 臨鍵鎖 | ||
等值查詢 | 查詢的值存在 | 臨鍵鎖+間隙鎖 | ||
查詢的值不存在 | 間隙鎖 | |||
唯一索引 | 范圍查詢 | 行鎖+間隙鎖 | ||
等值查詢 | 查詢的值存在 | 行鎖 | ||
查詢的值不存在 | 間隙鎖 |
具體加鎖過(guò)程可見(jiàn)如下連接:
間隙鎖詳解https://blog.csdn.net/w15558056319/article/details/122861509?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172309730016800182785516%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=172309730016800182785516&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-23-122861509-null-null.142^v100^pc_search_result_base5&utm_term=%E9%97%B4%E9%9A%99%E9%94%81&spm=1018.2226.3001.4187