深入理解MySQL數(shù)據(jù)庫各種鎖(總結(jié))

0. 對MySQL的鎖了解嗎

  • 當(dāng)數(shù)據(jù)庫有并發(fā)事務(wù)的時候簇宽,可能會產(chǎn)生數(shù)據(jù)的不一致函似,這時候需要一些機制來保證訪問的次序,鎖機制就是這樣的一個機制喘垂。

  • 就像酒店的房間,如果大家隨意進(jìn)出绍撞,就會出現(xiàn)多人搶奪同一個房間的情況正勒,而在房間上裝上鎖,申請到鑰匙的人才可以入住并且將房間鎖起來傻铣,其他人只有等他使用完畢才可以再次使用章贞。

  • 鎖的作用:用于管理對共享資源的并發(fā)訪問,保證數(shù)據(jù)庫的完整性和一致性

1. 隔離級別與鎖的關(guān)系

  • 在Read Uncommitted級別下非洲,讀取數(shù)據(jù)不需要加共享鎖阱驾,這樣就不會跟被修改的數(shù)據(jù)上的排他鎖沖突

  • 在Read Committed級別下就谜,讀操作需要加共享鎖,但是在語句執(zhí)行完以后釋放共享鎖里覆;

  • 在Repeatable Read級別下,讀操作需要加共享鎖缆瓣,但是在事務(wù)提交之前并不釋放共享鎖喧枷,也就是必須等待事務(wù)執(zhí)行完畢以后才釋放共享鎖。

  • SERIALIZABLE 是限制性最強的隔離級別弓坞,因為該級別鎖定整個范圍的鍵隧甚,并一直持有鎖,直到事務(wù)完成渡冻。

2. MySQL三種鎖的級別戚扳。按照鎖的粒度分?jǐn)?shù)據(jù)庫鎖有哪些?鎖機制與InnoDB鎖算法

在關(guān)系型數(shù)據(jù)庫中族吻,可以按照鎖的粒度把數(shù)據(jù)庫鎖分為行級鎖(INNODB引擎)帽借、表級鎖(MYISAM引擎)和頁級鎖(BDB引擎 )

MyISAM和InnoDB存儲引擎使用的鎖:

  • MyISAM采用表級鎖(table-level locking)超歌。

  • InnoDB支持行級鎖(row-level locking)和表級鎖砍艾,默認(rèn)為行級鎖

表級鎖

  • 表級鎖是MySQL中鎖定粒度最大的一種鎖,表示對當(dāng)前操作的整張表加鎖巍举,它實現(xiàn)簡單脆荷,資源消耗較少,被大部分MySQL引擎支持懊悯。最常使用的MYISAM與INNODB都支持表級鎖定蜓谋。表級鎖定分為表共享讀鎖(共享鎖)與表獨占寫鎖(排他鎖)

  • 特點

    • 開銷小炭分,加鎖快桃焕;

    • 不會出現(xiàn)死鎖;

    • 鎖定粒度大欠窒,發(fā)生鎖沖突的概率最高覆旭,并發(fā)度最低

行級鎖

  • 行級鎖是Mysql中鎖定粒度最細(xì)的一種鎖岖妄,表示只針對當(dāng)前操作的行進(jìn)行加鎖型将。

  • 行級鎖能大大減少數(shù)據(jù)庫操作的沖突。其加鎖粒度最小荐虐,但加鎖的開銷也最大七兜。行級鎖分為 共享鎖 和 排他鎖。

  • 特點

    • 開銷大福扬,加鎖慢;

    • 會出現(xiàn)死鎖;

    • 鎖定粒度最小柔袁,發(fā)生鎖沖突的概率最低军援,并發(fā)度也最高

頁面鎖

  • 頁級鎖是MySQL中鎖定粒度介于行級鎖和表級鎖中間的一種鎖摄乒。

  • 表級鎖速度快,但沖突多,行級沖突少莉御,但速度慢。所以取了折衷的頁級俗冻,一次鎖定相鄰的一組記錄礁叔。

  • 特點

    • 開銷和加鎖時間界于表鎖和行鎖之間;

    • 會出現(xiàn)死鎖迄薄;

    • 鎖定粒度界于表鎖和行鎖之間琅关,并發(fā)度一般

封鎖粒度小:

  • 好處:鎖定的數(shù)據(jù)量越少讥蔽,發(fā)生鎖爭用的可能就越小涣易,系統(tǒng)的并發(fā)程度就越高;

  • 壞處:系統(tǒng)開銷大(加鎖勤篮、釋放鎖都毒、檢查鎖的狀態(tài)都需要消耗資源)

3. MySQL常見的鎖類型?

排它鎖(Exclusive Lock)/ X鎖

  • 排他鎖又叫做寫鎖碰缔。 當(dāng)用戶要進(jìn)行數(shù)據(jù)的寫入時账劲,對數(shù)據(jù)加上排他鎖。排他鎖只可以加一個金抡,他和其他的排他鎖瀑焦,共享鎖都相斥。

  • 事務(wù)對數(shù)據(jù)加上X鎖時梗肝,只允許此事務(wù)讀取和修改此數(shù)據(jù)榛瓮,并且其它事務(wù)不能對該數(shù)據(jù)加任何鎖

SELECT * FROM table_name WHERE ... FOR UPDATE巫击;   # 排它鎖

共享鎖(Shared Lock)/ S鎖

  • 共享鎖又叫做讀鎖禀晓。 當(dāng)用戶要進(jìn)行數(shù)據(jù)的讀取時,對數(shù)據(jù)加上共享鎖坝锰。共享鎖可以同時加上多個粹懒。

  • 加了S鎖后,該事務(wù)只能對數(shù)據(jù)進(jìn)行讀取而不能修改顷级,并且其它事務(wù)只能加S鎖凫乖,不能加X鎖

  • 場景:相當(dāng)于對于同一把門,它擁有多個鑰匙一樣。

  • 在執(zhí)行語句后面加上lock in share mode就代表對某些資源加上共享鎖了帽芽。

SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE;  # 共享鎖

意向鎖(Intention Locks)

意向鎖都是表鎖删掀。意向鎖的存在是為了允許事務(wù)在行級上的鎖和表級上的鎖同時存在。

  • 意向共享鎖(IS Lock)事務(wù)想要在獲得表中某些記錄的共享鎖导街,需要在表上先加意向共享鎖披泪。

  • 意向排他鎖(IX Lock)事務(wù)想要在獲得表中某些記錄的互斥鎖,需要在表上先加意向互斥鎖搬瑰。

由于InnoDB存儲引擎支持的是行級別的鎖付呕,因此意向鎖(因為意向鎖是表鎖)其實不會阻塞除全表掃以外的任何請求。故表級意向鎖與行級鎖的兼容性如下所示

是否兼容當(dāng)前鎖模式 X IX S IS
X 沖突 沖突 沖突 沖突
IX 沖突 兼容 沖突 兼容
S 沖突 沖突 兼容 兼容
IS 沖突 兼容 兼容 兼容
  • IS/IX 鎖之間都是兼容的跌捆;

  • 好處:如果一個事務(wù)想要對整個表加X鎖,就需要先檢測是否有其它事務(wù)對該表或者該表中的某一行加了鎖象颖,這種檢測非常耗時佩厚。有了意向鎖之后,只需要檢測整個表是否存在IX/IS/X/S鎖就行了

意向鎖到底有什么作用

  • innodb的意向鎖主要用于解決多粒度的鎖并存的情況说订。

  • 比如事務(wù)A要在一個表上加S鎖抄瓦,如果表中的一行已被事務(wù)B加了X鎖,那么該鎖的申請也應(yīng)被阻塞陶冷。

  • 如果表中的數(shù)據(jù)很多钙姊,逐行檢查鎖標(biāo)志的開銷將很大,系統(tǒng)的性能將會受到影響埂伦。

  • 為了解決這個問題煞额,可以在表級上引入新的鎖類型來表示其所屬行的加鎖情況,這就引出了“意向鎖”的概念沾谜。

  • 舉個例子膊毁,如果表中記錄1億,事務(wù)A把其中有幾條記錄上了行鎖了基跑,這時事務(wù)B需要給這個表加表級鎖婚温,如果沒有意向鎖的話,那就要去表中查找這一億條記錄是否上鎖了媳否。如果存在意向鎖栅螟,那么假如事務(wù)A在更新一條記錄之前,先加意向鎖篱竭,再加X鎖力图,事務(wù)B先檢查該表上是否存在意向鎖,存在的意向鎖是否與自己準(zhǔn)備加的鎖沖突室抽,如果有沖突搪哪,則等待直到事務(wù)A釋放,而無須逐條記錄去檢測。事務(wù)B更新表時晓折,其實無須知道到底哪一行被鎖了惑朦,它只要知道反正有一行被鎖了就行了。

  • 主要作用是處理行鎖和表鎖之間的矛盾漓概,能夠顯示“某個事務(wù)正在某一行上持有了鎖漾月,或者準(zhǔn)備去持有鎖”

4. 知道m(xù)ysql中的鎖嗎,說一下表鎖胃珍,行鎖梁肿,如何上鎖(for update),舉個例子在什么時候事務(wù)會進(jìn)入阻塞狀態(tài)

  • 表級鎖:開銷小觅彰,加鎖快吩蔑;不會出現(xiàn)死鎖;鎖定粒度大填抬,發(fā)生鎖沖突的概率最高,并發(fā)度最低烛芬。

  • 行級鎖:開銷大,加鎖慢飒责;會出現(xiàn)死鎖赘娄;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高宏蛉。

  • 因為不同鎖之間的兼容性關(guān)系遣臼,在有些時刻一個事務(wù)中的鎖需要等待另一個事務(wù)中的鎖釋放它占有的資源,這就是阻塞拾并。

5. mysql共享鎖與排他鎖

參考

共享鎖與排他鎖是行級鎖

  • 共享鎖又稱為讀鎖揍堰,簡稱S鎖,顧名思義辟灰,共享鎖就是多個事務(wù)對于同一數(shù)據(jù)可以共享一把鎖个榕,都能訪問到數(shù)據(jù),但是只能讀不能修改芥喇。

  • 排他鎖又稱為寫鎖西采,簡稱X鎖,顧名思義继控,排他鎖就是不能與其他所并存械馆,如一個事務(wù)獲取了一個數(shù)據(jù)行的排他鎖,其他事務(wù)就不能再獲取該行的其他鎖武通,包括共享鎖和排他鎖霹崎,但是獲取排他鎖的事務(wù)是可以對數(shù)據(jù)就行讀取和修改

  • mysql InnoDB引擎默認(rèn)的修改數(shù)據(jù)語句冶忱,update,delete,insert都會自動給涉及到的數(shù)據(jù)加上排他鎖尾菇,select語句默認(rèn)不會加任何鎖類型,如果加排他鎖可以使用select ...for update語句加共享鎖可以使用select ... lock in share mode語句派诬。所以加過排他鎖的數(shù)據(jù)行在其他事務(wù)種是不能修改數(shù)據(jù)的劳淆,也不能通過for update和lock in share mode鎖的方式查詢數(shù)據(jù),但可以直接通過select ...from...查詢數(shù)據(jù)默赂,因為普通查詢沒有任何鎖機制沛鸵。

image

6. 行鎖的三種算法,以及解決的問題

參考

InnoDB行鎖時通過給索引上的索引項加鎖來實現(xiàn)的缆八,Oracle時通過在數(shù)據(jù)塊中相對應(yīng)數(shù)據(jù)行加鎖來實現(xiàn)曲掰。

InnoDB這種行鎖實現(xiàn)特點意味著,只有通過索引條件檢索條件數(shù)據(jù)奈辰,InnoDB才使用行鎖栏妖,否則InnoDB將使用表鎖。

行鎖的三種算法:

  • Record鎖:單個記錄上的鎖??

  • gap鎖:間隙鎖奖恰,鎖定一個范圍底哥,但不包含記錄本身

  • next-key鎖:Gap Lock + Record Lock,鎖定一個范圍房官,并且鎖定記錄本身

image

記錄鎖 Record Locks

  • 單個記錄上的鎖

  • Record Lock是對索引項加鎖。記錄鎖有兩種模式续滋,S模式和X模式翰守。

  • 記錄鎖總會鎖住索引記錄,鎖住的是key疲酌。

  • 即使表沒有建立索引蜡峰,InnoDB也會創(chuàng)建一個隱藏的聚簇索引(隱藏的遞增主鍵索引),并使用此索引進(jìn)行記錄鎖定朗恳。

  • 場景:一個索引有10,11,13,20這4個值湿颅, Innodb可以使用記錄鎖 Record Locks 將10,11粥诫,13油航,20這四個索引鎖住

間隙鎖 Gap Locks

  • 間隙鎖,鎖定一個范圍怀浆,但不包含記錄本身

  • 間隙鎖作用在索引記錄之間的間隔谊囚,又或者作用在第一個索引之前,最后一個索引之后的間隙执赡。不包括索引本身镰踏。

  • 例如

SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;

這條語句阻止其他事務(wù)插入10和20之間的數(shù)字,無論這個數(shù)字是否存在沙合。 間隙可以跨越0個奠伪,單個或多個索引值。

  • InnoDB中的間隙鎖的唯一目的是防止其他事務(wù)插入間隙。

  • 間隙鎖時針對事務(wù)隔離級別為可重復(fù)讀或以上級別而配的绊率。如果事務(wù)隔離級別改為RC谨敛,則間隙鎖會被禁用。

  • Gap Lock在InnoDB的唯一作用就是防止其他事務(wù)的插入操作即舌,以此防止幻讀

  • 場景:一個索引有10,11,13,20這4個值佣盒, Innodb可以使用間隙鎖 Gap Lock 將(-∞,10),(10,11)顽聂,(11,13)肥惭,(13,20),(20, +∞)這五個范圍鎖住??

Next-key鎖

  • Gap Lock+Record Lock紊搪,鎖定一個范圍蜜葱,并且鎖定記錄本身

  • Next-key鎖是在下一個索引記錄本身和索引之前的gap加上S鎖或是X鎖(如果是讀就加上S鎖(共享鎖),如果是寫就加X鎖(排他鎖))耀石。

  • InnoDB使用next-key鎖對索引進(jìn)行掃描和搜索牵囤,這樣就讀取不到幻象行,避免了幻讀的發(fā)生滞伟。

  • 當(dāng)查詢的索引含有唯一屬性時揭鳞,InnoDB存儲引擎會對Next-Key Lock 進(jìn)行優(yōu)化,將其降級為 Record Lock梆奈,即僅鎖住索引本身野崇,而不是范圍。

    當(dāng)查詢的索引為輔助索引時亩钟,默認(rèn)使用Next-Key Locking技術(shù)進(jìn)行加鎖乓梨,鎖定范圍是前一個索引到后一個索引之間范圍。

  • 場景:一個索引有10,11,13,20這4個值清酥, 那么Next-key鎖 鎖住的范圍 (-∞,10]扶镀,(10,11],(11,13]焰轻,(13,20]臭觉,(20, +∞),這五個范圍是左閉右開的辱志,可以看出他不僅鎖住了一個范圍胧谈,也會鎖定記錄本身。

  • InnoDB這種行鎖的實現(xiàn)特點意味著荸频,如果不通過索引條件檢索數(shù)據(jù)菱肖,那么InnoDB將對表中的所有記錄加鎖,實際效果跟鎖表一樣旭从。

  • 采用Next-Key Lock的鎖定技術(shù)稱為Next-Key Locking稳强。這種設(shè)計的目的是為了解決幻讀(Phantom Problem)场仲。利用這種鎖定技術(shù),鎖定的不是單個值退疫,而是一個范圍渠缕。

7. 實現(xiàn)一個讀寫鎖

https://blog.csdn.net/u014316026/article/details/78726459

  • 讀鎖(共享鎖)是讀取操作創(chuàng)建的鎖。其他用戶可以并發(fā)讀取數(shù)據(jù)褒繁,但任何事務(wù)都不能對數(shù)據(jù)進(jìn)行修改(獲取數(shù)據(jù)上的排他鎖)亦鳞,直到已釋放所有共享鎖。 如果事務(wù)T對數(shù)據(jù)A加上共享鎖后棒坏,則其他事務(wù)只能對A再加共享鎖燕差,不能加排他鎖。獲準(zhǔn)共享鎖的事務(wù)只能讀數(shù)據(jù)坝冕,不能修改數(shù)據(jù)徒探。

  • 寫鎖(排他鎖)如果事務(wù)T對數(shù)據(jù)A加上排他鎖后,則其他事務(wù)不能再對A加任任何類型的封鎖喂窟。獲準(zhǔn)排他鎖的事務(wù)既能讀數(shù)據(jù)测暗,又能修改數(shù)據(jù)

  • 事務(wù)可以通過以下語句給sql加共享鎖和排他鎖:

    • 共享鎖:select …… lock in share mode;

    • 排他鎖:select …… for update;

共享鎖:

image

排他鎖:

image

8. 什么是三級封鎖協(xié)議磨澡?

一級封鎖協(xié)議

  • 修改數(shù)據(jù)加x鎖直到事務(wù)結(jié)束才釋放碗啄。可以解決丟失修改問題(兩個事務(wù)不能同時對一個數(shù)據(jù)加X鎖,避免了修改被覆蓋)稳摄;

  • 在一級封鎖協(xié)議中挫掏,讀數(shù)據(jù)是不需要加鎖的,它修改數(shù)據(jù)加x鎖直到事務(wù)結(jié)束才釋放秩命。。

二級封鎖協(xié)議

  • 在一級的基礎(chǔ)上褒傅,事務(wù)在讀取數(shù)據(jù)之前必須先加S鎖弃锐,讀完后釋放S鎖。可以解決臟讀問題(如果已經(jīng)有事務(wù)在修改數(shù)據(jù)殿托,就意味著已經(jīng)加了X鎖霹菊,此時想要讀取數(shù)據(jù)的事務(wù)并不能加S鎖,也就無法進(jìn)行讀取支竹,避免了讀取臟數(shù)據(jù))旋廷;

  • 二級封鎖協(xié)議除防止了丟失修改,還可以進(jìn)一步防止讀“臟”數(shù)據(jù)礼搁。但在二級封鎖協(xié)議中饶碘,由于讀完數(shù)據(jù)后即可釋放S鎖,所以它不能保證可重復(fù)讀馒吴。

三級封鎖協(xié)議

  • 在二級的基礎(chǔ)上扎运,事務(wù)在讀取數(shù)據(jù)之前必須先加S鎖瑟曲,直到事務(wù)結(jié)束才能釋放

  • 可以解決不可重復(fù)讀問題(避免了在事務(wù)結(jié)束前其它事務(wù)對數(shù)據(jù)加X鎖進(jìn)行修改豪治,保證了事務(wù)期間數(shù)據(jù)不會被其它事務(wù)更新)

  • 上述三級協(xié)議的主要區(qū)別在于什么操作需要申請封鎖洞拨,以及何時釋放。

9. 什么是兩段鎖協(xié)議负拟?

https://www.cnblogs.com/mysql-hang/articles/11027685.html

  • 事務(wù)必須嚴(yán)格分為兩個階段對數(shù)據(jù)進(jìn)行加鎖和解鎖的操作烦衣,第一階段加鎖,第二階段解鎖掩浙。也就是說一個事務(wù)中一旦釋放了鎖花吟,就不能再申請新鎖了。

  • 目的:引入2PL是為了保證事務(wù)的隔離性涣脚,保證并發(fā)調(diào)度的準(zhǔn)確性示辈,多個事務(wù)在并發(fā)的情況下依然是串行的。

  • 可串行化調(diào)度是指遣蚀,通過并發(fā)控制矾麻,使得并發(fā)執(zhí)行的事務(wù)結(jié)果與某個串行執(zhí)行的事務(wù)結(jié)果相同。事務(wù)遵循兩段鎖協(xié)議是保證可串行化調(diào)度的充分條件

  • 傳統(tǒng)RDBMS加鎖的一個原則芭梯,就是2PL (二階段鎖):Two-Phase Locking险耀。相對而言,2PL比較容易理解玖喘,說的是鎖操作分為兩個階段:加鎖階段與解鎖階段甩牺,并且保證加鎖階段與解鎖階段不相交。下面累奈,仍舊以MySQL為例贬派,來簡單看看2PL在MySQL中的實現(xiàn)。

image
  • 從上圖可以看出澎媒,2PL就是將加鎖/解鎖分為兩個完全不相交的階段搞乏。加鎖階段:只加鎖,不放鎖戒努。解鎖階段:只放鎖请敦,不加鎖。

  • 2PL主要用于Mysql(僅限innodb)中使用的储玫。保證事務(wù)的一致性與隔離性侍筛。

10. 什么是樂觀鎖和悲觀鎖?

樂觀鎖

樂觀鎖不是數(shù)據(jù)庫自帶的撒穷,需要我們自己去實現(xiàn)匣椰。樂觀鎖是指操作數(shù)據(jù)庫時(更新操作),想法很樂觀端礼,認(rèn)為這次的操作不會導(dǎo)致沖突窝爪,在操作數(shù)據(jù)時弛车,并不進(jìn)行任何其他的特殊處理(也就是不加鎖),而在進(jìn)行更新后蒲每,再去判斷是否有沖突了纷跛。

樂觀鎖:總是假設(shè)最好的情況,每次去拿數(shù)據(jù)的時候都認(rèn)為別人不會修改(天真)邀杏,操作數(shù)據(jù)時不會上鎖贫奠,但是更新時會判斷在此期間有沒有別的事務(wù)更新這個數(shù)據(jù),若被更新過望蜡,則失敗重試唤崭;適用于讀多寫少的場景。

樂觀鎖的實現(xiàn)方式有:

  1. 版本號機制:加一個版本號或者時間戳字段脖律,每次數(shù)據(jù)更新時同時更新這個字段谢肾;

    • 一般是在數(shù)據(jù)表中加上一個數(shù)據(jù)版本號version字段,表示數(shù)據(jù)被修改的次數(shù)小泉,當(dāng)數(shù)據(jù)被修改時芦疏,version值會加一。當(dāng)線程A要更新數(shù)據(jù)值時微姊,在讀取數(shù)據(jù)的同時也會讀取version值酸茴,在提交更新時,若剛才讀取到的version值為當(dāng)前數(shù)據(jù)庫中的version值相等時才更新兢交,否則重試更新操作薪捍,直到更新成功。

    • 場景:

      • 假設(shè)數(shù)據(jù)庫中帳戶信息表中有一個 version 字段配喳,當(dāng)前值為 1 酪穿;而當(dāng)前帳戶余額字段( balance )為 $100 。

      • 操作員 A 此時將其讀出( version=1 )晴裹,并從其帳戶余額中扣除 50(100-$50 )被济。

      • 在操作員 A 操作的過程中,操作員B 也讀入此用戶信息( version=1 )息拜,并從其帳戶余額中扣除 20 (100-$20 )。

      • 操作員 A 完成了修改工作净响,將數(shù)據(jù)版本號加一( version=2 )少欺,連同帳戶扣除后余額( balance=$50 ),提交至數(shù)據(jù)庫更新馋贤,此時由于提交數(shù)據(jù)版本大于數(shù)據(jù)庫記錄當(dāng)前版本赞别,數(shù)據(jù)被更新,數(shù)據(jù)庫記錄 version 更新為 2 配乓。

      • 操作員 B 完成了操作仿滔,也將版本號加一( version=2 )試圖向數(shù)據(jù)庫提交數(shù)據(jù)( balance=$80 )惠毁,但此時比對數(shù)據(jù)庫記錄版本時發(fā)現(xiàn),操作員 B 提交的數(shù)據(jù)版本號為 2 崎页,數(shù)據(jù)庫記錄當(dāng)前版本也為 2 鞠绰,不滿足 “ 提交版本必須大于記錄當(dāng)前版本才能執(zhí)行更新 “ 的樂觀鎖策略,因此飒焦,操作員 B 的提交被駁回蜈膨。

      • 這樣,就避免了操作員 B 用基于 version=1 的舊數(shù)據(jù)修改的結(jié)果覆蓋操作員A 的操作結(jié)果的可能牺荠。

    • 使用實例:

    1. SELECT data AS old_data, version AS old_version FROM …;
    2. 根據(jù)獲取的數(shù)據(jù)進(jìn)行業(yè)務(wù)操作翁巍,得到new_data和new_version
    3. UPDATE SET data = new_data, version = new_version WHERE version = old_version
    if (updated row > 0) {
    // 樂觀鎖獲取成功,操作完成
    } else {
    // 樂觀鎖獲取失敗休雌,回滾并重試
    }
  1. CAS算法:compare and swap(比較與交換)灶壶,是一種有名的無鎖算法。先讀取想要更新的字段或者所有字段杈曲,更新的時候比較一下驰凛,只有字段沒有變化才進(jìn)行更新。一般情況下是一個自旋操作鱼蝉,即不斷的重試

    • 無鎖編程洒嗤,即不使用鎖的情況下實現(xiàn)多線程之間的變量同步,也就是在沒有線程被阻塞的情況下實現(xiàn)變量的同步魁亦,所以也叫非阻塞同步(Non-blocking Synchronization)渔隶。

    • CAS算法涉及到三個操作數(shù)

      • 需要讀寫的內(nèi)存值(內(nèi)存位置) V

      • 進(jìn)行比較的值(原值) A

      • 擬寫入的新值(新值) B

    • 當(dāng)且僅當(dāng) 內(nèi)存位置V 的值等于 原值A(chǔ) 時,CAS通過原子方式用 新值B 來更新V的值洁奈,否則不會執(zhí)行任何操作(比較和替換是一個原子操作)间唉。一般情況下是一個自旋操作,即不斷的重試利术。

    • CAS 有效地說明了“我認(rèn)為位置 V 應(yīng)該包含值 A呈野;如果包含該值,則將 B 放到這個位置印叁;否則被冒,不要更改該位置,只告訴我這個位置現(xiàn)在的值即可轮蜕。

樂觀鎖不是鎖昨悼,樂觀鎖是一種思想,版本號機制和CAS算法是實現(xiàn)這種思想的一種實現(xiàn)方式

  • 樂觀鎖的優(yōu)點:從上面的例子可以看出跃洛,樂觀鎖機制避免了長事務(wù)中的數(shù)據(jù)庫加鎖開銷率触,大大提升了大并發(fā)量下的系統(tǒng)整體性能表現(xiàn)。

  • 樂觀鎖的缺點:

    • ABA問題:

      • 如果一個變量V初次讀取的時候是A值汇竭,并且在準(zhǔn)備賦值的時候檢查到它仍然是A值葱蝗,那我們就能說明它的值沒有被其他線程修改過了嗎穴张?很明顯是不能的,因為在這段時間它的值可能被改為其他值两曼,然后又改回A皂甘,那CAS操作就會誤認(rèn)為它從來沒有被修改過。這個問題被稱為CAS操作的 "ABA"問題合愈。
    • 循環(huán)時間長開銷大

      • 自旋CAS(也就是不成功就一直循環(huán)執(zhí)行直到成功)如果長時間不成功叮贩,會給CPU帶來非常大的執(zhí)行開銷。
  • 總結(jié):讀用樂觀鎖佛析,寫用悲觀鎖益老。

悲觀鎖

悲觀鎖的實現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機制(也只有數(shù)據(jù)庫層提供的鎖機制才能真正保證數(shù)據(jù)訪問的排他性寸莫,否則捺萌,即使在本系統(tǒng)中實現(xiàn)了加鎖機制,也無法保證外部系統(tǒng)不會修改數(shù)據(jù))

  • 認(rèn)為數(shù)據(jù)隨時會被修改(被害妄想癥)膘茎,因此每次讀取數(shù)據(jù)之前都會上鎖桃纯,防止其它事務(wù)讀取或修改數(shù)據(jù)(共享資源每次只給一個線程使用,其它線程阻塞披坏,用完后再把資源轉(zhuǎn)讓給其它線程)态坦;

  • 應(yīng)用于數(shù)據(jù)更新比較頻繁的場景

  • 傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機制棒拂,比如行鎖伞梯,表鎖等,讀鎖帚屉,寫鎖等谜诫,都是在做操作之前先上鎖。

  • 悲觀鎖的實現(xiàn):首先實現(xiàn)悲觀鎖時攻旦,我們必須先使用set autocommit=0; 關(guān)閉mysql的autoCommit屬性喻旷。因為我們查詢出數(shù)據(jù)之后就要將該數(shù)據(jù)鎖定。

關(guān)閉自動提交后牢屋,我們需要手動開啟事務(wù)且预。

// 1.開始事務(wù)
begin; 或者 start transaction;
// 2.查詢出商品信息,然后通過for update鎖定數(shù)據(jù)防止其他事務(wù)修改
select status from t_goods where id=1 for update;
// 3.根據(jù)商品信息生成訂單
insert into t_orders (id,goods_id) values (null,1);
// 4.修改商品status為2
update t_goods set status=2;
// 5.提交事務(wù)
commit; --執(zhí)行完畢烙无,提交事務(wù)

上述就實現(xiàn)了悲觀鎖锋谐,悲觀鎖就是悲觀主義者,它會認(rèn)為我們在事務(wù)A中操作數(shù)據(jù)1的時候皱炉,一定會有事務(wù)B來修改數(shù)據(jù)1,所以怀估,在第2步我們將數(shù)據(jù)查詢出來后直接加上排它鎖(X)鎖狮鸭,防止別的事務(wù)來修改事務(wù)1合搅,直到我們commit后多搀,才釋放了排它鎖。

  • 優(yōu)點:保證了數(shù)據(jù)處理時的安全性灾部。

  • 缺點:加鎖造成了開銷增加康铭,并且增加了死鎖的機會。降低了并發(fā)性赌髓。

  • 樂觀鎖更新有可能會失敗从藤,甚至是更新幾次都失敗,這是有風(fēng)險的锁蠕。所以如果寫入居多夷野,對吞吐要求不高,可使用悲觀鎖荣倾。

11. 什么是死鎖悯搔?

  • 死鎖是指兩個或兩個以上事務(wù)在執(zhí)行過程中因爭搶鎖資源而造成的互相等待(形成環(huán)路)的現(xiàn)象

  • 表級鎖不會產(chǎn)生死鎖。所以解決死鎖主要還是針對于最常用的InnoDB舌仍。

  • 死鎖的關(guān)鍵在于:兩個(或以上)的Session加鎖的順序不一致妒貌。那么對應(yīng)的解決死鎖問題的關(guān)鍵就是:讓不同的session加鎖有次序。

12. 死鎖怎么解決?

  • 查出的線程殺死 kill SELECT trx_MySQL_thread_id FROM information_schema.INNODB_TRX;

  • 設(shè)置鎖的超時時間:Innodb 行鎖的等待時間铸豁,單位秒灌曙。可在會話級別設(shè)置节芥,RDS 實例該參數(shù)的默認(rèn)值為 50(秒)在刺。生產(chǎn)環(huán)境不推薦使用過大的 innodb_lock_wait_timeout參數(shù)值該參數(shù)支持在會話級別修改,方便應(yīng)用在會話級別單獨設(shè)置某些特殊操作的行鎖等待超時時間藏古,如下:set innodb_lock_wait_timeout=1000; —設(shè)置當(dāng)前會話 Innodb 行鎖等待超時時間增炭,單位秒。

  • 如果不同程序會并發(fā)存取多個表拧晕,盡量約定以相同的順序訪問表隙姿,可以大大降低死鎖機會。

  • 在同一個事務(wù)中厂捞,盡可能做到一次鎖定所需要的所有資源输玷,減少死鎖產(chǎn)生概率析恢;

  • 對于非常容易產(chǎn)生死鎖的業(yè)務(wù)部分逃默,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產(chǎn)生的概率空扎;

13. 鎖的優(yōu)化策略

  1. 讀寫分離
  2. 分段加鎖
  3. 減少鎖持有的時間
  4. 多個線程盡量以相同的順序去獲取資源
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末臭墨,一起剝皮案震驚了整個濱河市赔嚎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖尤误,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侠畔,死亡現(xiàn)場離奇詭異,居然都是意外死亡损晤,警方通過查閱死者的電腦和手機软棺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尤勋,“玉大人喘落,你說我怎么就攤上這事∽畋” “怎么了瘦棋?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長暖哨。 經(jīng)常有香客問我兽狭,道長,這世上最難降的妖魔是什么鹿蜀? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任箕慧,我火速辦了婚禮,結(jié)果婚禮上茴恰,老公的妹妹穿的比我還像新娘颠焦。我一直安慰自己,他們只是感情好往枣,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布伐庭。 她就那樣靜靜地躺著,像睡著了一般分冈。 火紅的嫁衣襯著肌膚如雪圾另。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天雕沉,我揣著相機與錄音集乔,去河邊找鬼。 笑死坡椒,一個胖子當(dāng)著我的面吹牛扰路,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播倔叼,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼汗唱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了丈攒?” 一聲冷哼從身側(cè)響起哩罪,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤授霸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后际插,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绝葡,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年腹鹉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敷硅。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡功咒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绞蹦,到底是詐尸還是另有隱情力奋,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布幽七,位于F島的核電站景殷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏澡屡。R本人自食惡果不足惜猿挚,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驶鹉。 院中可真熱鬧绩蜻,春花似錦、人聲如沸室埋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姚淆。三九已至孕蝉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腌逢,已是汗流浹背降淮。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留搏讶,地道東北人骤肛。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像窍蓝,于是被迫代替她去往敵國和親腋颠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354