mysql 共享锁_mysql有排他锁为什么还需要共享锁呢?
兩把鎖缺一不可,InnoDB 引擎中的四種隔離級(jí)別就是用 排他鎖 + 共享鎖 實(shí)現(xiàn)的。
下面是個(gè)人理解,可能并不嚴(yán)謹(jǐn)。
首先說一下并發(fā)可能產(chǎn)生的四種問題,如果你還不了解這四個(gè)問題,最好拿至少 20 分鐘時(shí)間模擬一下場(chǎng)景。
假設(shè)有兩個(gè)事務(wù)A,B,有一個(gè)資源值(一條記錄)是V;另外一個(gè)資源值(多條記錄的集合) VVV。
1.丟失修改:A 修改 V 為 v1, B 修改 V 為 v2。那么最后 V 是v1 還是 v2 呢?無論結(jié)果是什么,一定只有一個(gè)結(jié)果,那么另外一個(gè)修改就丟失了,因此叫做丟失修改。
2.臟讀:A 修改 V 為 v1, 但是修改不成功,事務(wù)會(huì)回滾。 在事務(wù) A 回滾的時(shí)候,B去讀取 V 的值,讀到的值是什么? 是 v1。 我們的 B 事務(wù)想期望的值是 V, 但是卻讀到了 v1,v1是一個(gè)臟數(shù)據(jù),因此我們簡(jiǎn)稱臟讀。
3.不可重復(fù)讀:這個(gè)場(chǎng)景下,A 事務(wù)要讀兩次 V 的值。 第一次直接讀取,然后停下,這個(gè)時(shí)候 B 事務(wù)去修改 V 的值為 v1,然后 A 事務(wù)再執(zhí)行它的第二次讀取。第一次讀到的是 V, 第二次讀到的是 v1,一個(gè)事務(wù)不同時(shí)間讀到的值不一樣,這個(gè)就是不可重復(fù)讀。
4.幻讀:這個(gè)場(chǎng)景的資源值不再是一個(gè)記錄了,而是很多記錄的一個(gè)集合,我們叫它 VVV(假設(shè)有三條記錄,分別為 v1,v2,v3)。A 事務(wù)讀到了 VVV 集合,再使用它之前,B 事務(wù)把集合中的 v3 值刪除了,這個(gè)時(shí)候我們?nèi)ナ褂眠@個(gè)集合中的 v3, 但是發(fā)現(xiàn)值不在這里了,我們所讀到的集合就是一個(gè)不真實(shí)的集合?;米x的資源一定要是一個(gè)集合,修改(刪除也被認(rèn)為是一種修改)會(huì)導(dǎo)致集合變化。
針對(duì)這四種問題,MySQL有四種不同的隔離級(jí)別,不同的隔離級(jí)別解決的問題不一樣。
1.讀未提交:解決丟失修改的問題。由上面可知,兩個(gè)事務(wù)同時(shí)修改一個(gè)資源值的時(shí)候,會(huì)發(fā)生修改丟失的問題。這個(gè)時(shí)候我們對(duì)資源加一個(gè)排他鎖,加鎖以后,資源只能由一個(gè)事務(wù)所擁有,修改完畢以后另外一個(gè)事務(wù)才可以拿到資源。這就解決了丟失修改的問題。(資源值加 X 鎖,事務(wù)結(jié)束釋放)。
2.讀提交:解決臟讀問題。在 1 的基礎(chǔ)上(給資源加 X 鎖,直到事務(wù)結(jié)束),增加一個(gè) S 鎖。 讀數(shù)據(jù)的時(shí)候給數(shù)據(jù)加一個(gè) S 鎖, 資源在有 X 鎖的時(shí)候,S 鎖是加不上去的,因此直到事務(wù)結(jié)束, S 鎖才可以加上去, 事務(wù)都結(jié)束了,自然不會(huì)讀到臟數(shù)據(jù)。(寫數(shù)據(jù)加 X 鎖,事務(wù)結(jié)束釋放,讀數(shù)據(jù)加 S 鎖,讀完數(shù)據(jù)立即釋放)
3.可重復(fù)讀:上一個(gè)隔離級(jí)別中,讀的時(shí)候加 S 鎖。 在不可重復(fù)讀的問題里面:
a.第一次讀,加 S 鎖,得到 V,釋放 S 鎖;
b. 然后 B 事務(wù)修改 V 為 v1,加了 X 鎖,事務(wù)結(jié)束后釋放;
c.第二次讀,加 S 鎖,得到 v1,釋放 S 鎖。
是不是不可重復(fù)的問題還是存在?怎么解決呢? 將我們的 S 鎖設(shè)定為,一個(gè)事務(wù)結(jié)束后才釋放。 加了這個(gè)限定條件以后, B 事務(wù)就無法修改 V, 因?yàn)?V 現(xiàn)在加了 S 鎖,只能被讀,無法被修改。(寫數(shù)據(jù)加 X 鎖,事務(wù)結(jié)束釋放,讀數(shù)據(jù)加 S 鎖,事務(wù)結(jié)束釋放)
4.串行化,串行化是事務(wù)完全按照 ACID 的四個(gè)原則來執(zhí)行,這種情況效率比較低,很少用。
這樣一說了,你覺得共享鎖還是多余的嗎?
各位姥爺,能理解的點(diǎn)個(gè)贊啊。
再針對(duì)具體問題做一個(gè)解釋。
select *from table_name for update; // 加 X 鎖
select *from table_name for share; // 加 S 鎖,MySQL 版本 8.0 以后。
select *from table_name lock in share mode; 加 S 鎖, MySQL 版本 8.0 以前。
示例: 1. 首先開始一個(gè)事務(wù)A,并且關(guān)閉自動(dòng)提交。
START TRANSACTION;
set autocommit = 0;
2. 然后在查詢條件下加一把 X 鎖
SELECT*FROM table_name for UPDATE;
3. 接下來你再開一個(gè)查詢窗口,開不開事務(wù)都沒關(guān)系,給查詢加一把 S 鎖
SELECT *FROM person LOCK IN SHARE MODE; // 我的版本是 MySQL 5.6
執(zhí)行這條查詢 SQL 的時(shí)候,就會(huì)被堵塞。原因是你在 事務(wù)A 中給表加了 X 鎖,再給表加 S 鎖的時(shí)候就會(huì)堵塞。
當(dāng)然,你可以先加 S 鎖,再去加 X 鎖的時(shí)候同樣會(huì)被堵塞。
希望看明白了可以點(diǎn)個(gè)贊。
總結(jié)
以上是生活随笔為你收集整理的mysql 共享锁_mysql有排他锁为什么还需要共享锁呢?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java坐标移动题目case_用java
- 下一篇: spark中dataframe解析_Sp