MySQL-鎖 個(gè)人理解

行鎖

對(duì)數(shù)據(jù)庫表行記錄進(jìn)行加鎖。
比如:id為 table1 表主鍵
當(dāng) id=1 數(shù)據(jù) 存在 的情況下,SQL語句:
update table1 set field1=param1 where id=1;
(
或 delete from table1 where id=1;
或 select * from table1 where id=1 for update;
)
實(shí)則是當(dāng)前事務(wù)(事務(wù)T)對(duì) id=1的這行數(shù)據(jù) 加的 行鎖,直到事務(wù)提交或回滾,鎖釋放。

寫鎖、排他鎖(X鎖)

如上例子,實(shí)則也是對(duì)id=1的這行數(shù)據(jù)加的是一個(gè)寫鎖,它是一個(gè)排他鎖。
排他鎖(X鎖):
若 事務(wù)T 對(duì) 數(shù)據(jù)a 加上X鎖 ,事務(wù)T 就具備了 數(shù)據(jù)a 的讀寫權(quán)限,其它事務(wù)不能再對(duì) 數(shù)據(jù)a 加任何鎖,直到 事務(wù)T 釋放 數(shù)據(jù)a 上的鎖。

行鎖 一定是 排他鎖嗎?

不一定!
行鎖字面意思 就是 對(duì) 行進(jìn)行加鎖,只要對(duì)行進(jìn)行加鎖都可以叫行鎖。但是從另一個(gè)層面講,對(duì)這 行數(shù)據(jù) 進(jìn)行加鎖不是非得加 排他鎖,也可以對(duì)行數(shù)據(jù)加 共享鎖;如下
SELECT * FROM table1 WHERE id=1 LOCK IN SHARE MODE;
在 id =1 數(shù)據(jù)存在的情況下 ,這里實(shí)則是對(duì) id=1的數(shù)據(jù)行加的 共享鎖LOCK IN SHARE MODE;

讀鎖、共享鎖(S鎖)

如:

SELECT * FROM table1 WHERE id=1 LOCK IN SHARE MODE;

若事務(wù)T對(duì)數(shù)據(jù)對(duì)象A加上S鎖,在事務(wù)T未釋放數(shù)據(jù)A的S鎖之前,其它事務(wù)也可以對(duì)數(shù)據(jù)對(duì)象A加S鎖,針對(duì)數(shù)據(jù)A上的這把鎖是共享的,所以叫 共享鎖

但是 在兩個(gè)事務(wù)都持有了數(shù)據(jù)A的S鎖之后,事務(wù)1未結(jié)束前是不允許事務(wù)2 針對(duì) 鎖定的數(shù)據(jù) 做 具體寫操作的,同樣,事務(wù)2在未結(jié)束前也不允許事務(wù)1 對(duì)鎖定的數(shù)據(jù)做 寫操作。

如果 事務(wù)1 事務(wù)2 持有了同一把 共享鎖,如果這時(shí) 事務(wù)1 對(duì)鎖定的數(shù)據(jù) 做寫操作,那么會(huì)被阻塞。如果事務(wù)2 在事務(wù)1被阻塞的情況下 也執(zhí)行寫操作,那么會(huì)出現(xiàn)死鎖問題。

其它情況下的共享鎖:
當(dāng)主鍵id=1的數(shù)據(jù)不存在時(shí),MySQL RR(默認(rèn)事務(wù)隔離級(jí)別——可重復(fù)讀) 隔離級(jí)別下,如下:
select * from table1 where id = 1 for update;

update table1 set filed1=param1 where id = 1;

INSERT INTO table1
SELECT 1,'Tom','male','19' FROM DUAL
WHERE NOT EXISTS (SELECT *FROM table1 where id = 1);
如上三條SQL語句,實(shí)則也是 對(duì) id=1 所處的 主鍵間隙空間 加的 共享鎖,這里 也是 一個(gè) 間隙鎖。(RC不存在間隙鎖)

圖解 S鎖與X鎖 兼容、互斥關(guān)系


image.png

間隙鎖(Gap Lock)

條件:RR事務(wù)隔離級(jí)別下
鎖加在不存在的空閑空間,可以是兩個(gè)索引記錄之間,也可能是第一個(gè)索引記錄之前或最后一個(gè)索引之后的空間。
間隙鎖是封鎖索引記錄中的間隔,或者第一條索引記錄之前的范圍,又或者最后一條索引記錄之后的范圍。

下圖就是六條記錄,并且形成了7個(gè)間隙。 那么對(duì)間隙上鎖,就是間隙鎖。


image.png

間隙鎖可能出現(xiàn)的問題演示
演示1:

image.png

image.png

如上圖,如果事務(wù)1 步驟5 插入的是 id= 98 ,事務(wù)2 步驟6 插入的是 id=99 數(shù)據(jù),那么 不會(huì)出現(xiàn) 阻塞 死鎖問題。

演示2:


image.png

表鎖

對(duì)整個(gè)表進(jìn)行上鎖的操作,叫表鎖
對(duì)表進(jìn)行加鎖
LOCK TABLES table_name WRITE/READ;
解鎖 (釋放當(dāng)前會(huì)話所加的表鎖)
UNLOCK TABLES;

如上方式對(duì)表進(jìn)行加鎖,是一種絕對(duì)加鎖的方式。

如果 對(duì)表 加了寫鎖 以后,其它 會(huì)話,無法讀表中任何數(shù)據(jù)(普通select也不行),無法做任何修改,只能阻塞,直到 表鎖 釋放;

如果 對(duì)表 加了讀鎖 以后,其它會(huì)話可以 繼續(xù)讀取數(shù)據(jù),或者繼續(xù)對(duì)表加讀鎖(共享鎖),但是在加了讀鎖之后,其它會(huì)話就不能去修改表中任何數(shù)據(jù),直到鎖釋放;

如下 操作,也會(huì) 對(duì) 表整個(gè)范圍進(jìn)行加鎖(不同種類鎖,范圍覆蓋整個(gè)表,也叫表鎖)。

在RR的隔離級(jí)別下,當(dāng)color字段 為 非索引字段時(shí):
update table_name set field1=param1 where color='red';
全表掃描,最終導(dǎo)致 上鎖的范圍為整個(gè)表,其中有 X鎖 有 Gap鎖。


image.png

從鎖定范圍來講,這里也叫表鎖;

插入意向鎖(InnoDB)

多個(gè)事務(wù),在同一個(gè)索引,同一個(gè)范圍區(qū)間插入記錄時(shí),如果插入的位置不沖突,不會(huì)阻塞彼此。

在插入數(shù)據(jù)時(shí),會(huì)產(chǎn)生插入意向鎖,會(huì)對(duì)意向id位置進(jìn)行上鎖(非Gap鎖),屬于排他鎖;

事務(wù)1 插入id為1的數(shù)據(jù),掛起事務(wù)不提交,事務(wù)2 也插入id為1的數(shù)據(jù),則需要阻塞,直到事務(wù)1釋放 意向鎖。事務(wù)2 兩種結(jié)果:1、主鍵沖突,2、執(zhí)行成功;

如果事務(wù)1 插入id為1數(shù)據(jù),事務(wù)2插入id為2數(shù)據(jù),則互不影響。

如上內(nèi)容,如有 疑問,歡迎溝通指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容