什么是鎖?MySQL 中提供了幾類鎖命黔?
鎖是實(shí)現(xiàn)數(shù)據(jù)庫并發(fā)控制的重要手段呜呐,可以保證數(shù)據(jù)庫在多人同時操作時能夠正常運(yùn)行。MySQL 提供了全局鎖悍募、行級鎖蘑辑、表級鎖。其中 InnoDB
支持表級鎖和行級鎖坠宴,MyISAM 只支持表級鎖洋魂。
什么是死鎖?
是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中喜鼓,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去副砍。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的過程稱為死鎖庄岖。
死鎖是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中豁翎,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖隅忿,這些永遠(yuǎn)在互相等待的過程稱為死鎖心剥。
常見的死鎖案例有哪些?
- 將投資的錢拆封幾份借給借款人背桐,這時處理業(yè)務(wù)邏輯就要把若干個借款人一起鎖住 select * from xxx where id in (xx,xx,xx) for update优烧。
- 批量入庫,存在則更新链峭,不存在則插入畦娄。解決方法 insert into tab(xx,xx) on duplicate key update
xx
='xx'。
如何處理死鎖熏版?
對待死鎖常見的兩種策略:
- 通過 innodb lock wait_timeout 來設(shè)置超時時間纷责,一直等待直到超時;
- 發(fā)起死鎖檢測撼短,發(fā)現(xiàn)死鎖之后再膳,主動回滾死鎖中的某一個事務(wù),讓其它事務(wù)繼續(xù)執(zhí)行曲横。
如何查看死鎖喂柒?
- 使用命令
show engine innodb status
查看最近的一次死鎖不瓶。 - InnoDB Lock Monitor 打開鎖監(jiān)控,每 15s 輸出一次日志灾杰。使用完畢后建議關(guān)閉蚊丐,否則會影響數(shù)據(jù)庫性能。
如何避免死鎖艳吠?
- 為了在單個 InnoDB 表上執(zhí)行多個并發(fā)寫入操作時避免死鎖麦备,可以在事務(wù)開始時通過為預(yù)期要修改的每個元祖(行)使用 SELECT ... FOR UPDATE 語句來獲取必要的鎖,即使這些行的更改語句是在之后才執(zhí)行的昭娩。
- 在事務(wù)中凛篙,如果要更新記錄,應(yīng)該直接申請足夠級別的鎖栏渺,即排他鎖呛梆,而不應(yīng)先申請共享鎖、更新時再申請排他鎖磕诊,因?yàn)檫@時候當(dāng)用戶再申請排他鎖時填物,其他事務(wù)可能又已經(jīng)獲得了相同記錄的共享鎖,從而造成鎖沖突霎终,甚至死鎖
- 如果事務(wù)需要修改或鎖定多個表滞磺,則應(yīng)在每個事務(wù)中以相同的順序使用加鎖語句。在應(yīng)用中神僵,如果不同的程序會并發(fā)存取多個表雁刷,應(yīng)盡量約定以相同的順序來訪問表,這樣可以大大降低產(chǎn)生死鎖的機(jī)會
- 通過 SELECT ... LOCK IN SHARE MODE 獲取行的讀鎖后保礼,如果當(dāng)前事務(wù)再需要對該記錄進(jìn)行更新操作沛励,則很有可能造成死鎖。
- 改變事務(wù)隔離級別炮障。
InnoDB 默認(rèn)是如何對待死鎖的目派?
InnoDB 默認(rèn)是使用設(shè)置死鎖時間來讓死鎖超時的策略,默認(rèn) innodb lock wait_timeout 設(shè)置的時長是 50s胁赢。
如何開啟死鎖檢測企蹭?
設(shè)置 innodb deadlock detect 設(shè)置為 on 可以主動檢測死鎖,在 Innodb 中這個值默認(rèn)就是 on 開啟的狀態(tài)智末。
什么是全局鎖谅摄?它的應(yīng)用場景有哪些?
全局鎖就是對整個數(shù)據(jù)庫實(shí)例加鎖系馆,它的典型使用場景就是做全庫邏輯備份送漠。
這個命令可以使整個庫處于只讀狀態(tài)。使用該命令之后由蘑,數(shù)據(jù)更新語句闽寡、數(shù)據(jù)定義語句代兵、更新類事務(wù)的提交語句等操作都會被阻塞。
什么是共享鎖爷狈?
共享鎖又稱讀鎖 (read
lock)植影,是讀取操作創(chuàng)建的鎖。其他用戶可以并發(fā)讀取數(shù)據(jù)涎永,但任何事務(wù)都不能對數(shù)據(jù)進(jìn)行修改(獲取數(shù)據(jù)上的排他鎖)思币,直到已釋放所有共享鎖。當(dāng)如果事務(wù)對讀鎖進(jìn)行修改操作羡微,很可能會造成死鎖支救。
什么是排它鎖?
排他鎖 exclusive lock(也叫 writer lock)又稱寫鎖拷淘。
若某個事物對某一行加上了排他鎖,只能這個事務(wù)對其進(jìn)行讀寫指孤,在此事務(wù)結(jié)束之前启涯,其他事務(wù)不能對其進(jìn)行加任何鎖,其他進(jìn)程可以讀取,不能進(jìn)行寫操作恃轩,需等待其釋放结洼。
排它鎖是悲觀鎖的一種實(shí)現(xiàn),在上面悲觀鎖也介紹過叉跛。
若事務(wù) 1 對數(shù)據(jù)對象 A 加上 X 鎖松忍,事務(wù) 1 可以讀 A 也可以修改 A,其他事務(wù)不能再對 A 加任何鎖筷厘,直到事物 1 釋放 A
上的鎖鸣峭。這保證了其他事務(wù)在事物 1 釋放 A 上的鎖之前不能再讀取和修改 A。排它鎖會阻塞所有的排它鎖和共享鎖酥艳。
使用全局鎖會導(dǎo)致什么問題?
如果在主庫備份,在備份期間不能更新幢竹,業(yè)務(wù)停擺峻厚,所以更新業(yè)務(wù)會處于等待狀態(tài)。
如果在從庫備份骤铃,在備份期間不能執(zhí)行主庫同步的 binlog拉岁,導(dǎo)致主從延遲。
如何處理邏輯備份時惰爬,整個數(shù)據(jù)庫不能插入的情況喊暖?
如果使用全局鎖進(jìn)行邏輯備份就會讓整個庫成為只讀狀態(tài),幸好官方推出了一個邏輯備份工具 MySQLdump 來解決了這個問題补鼻,只需要在使用 MySQLdump
時哄啄,使用參數(shù) -single-transaction 就會在導(dǎo)入數(shù)據(jù)之前啟動一個事務(wù)來保證數(shù)據(jù)的一致性雅任,并且這個過程是支持?jǐn)?shù)據(jù)更新操作的。
如何設(shè)置數(shù)據(jù)庫為全局只讀鎖咨跌?
使用命令 flush tables with read lock
(簡稱 FTWRL)就可以實(shí)現(xiàn)設(shè)置數(shù)據(jù)庫為全局只讀鎖沪么。
除了 FTWRL 可以設(shè)置數(shù)據(jù)庫只讀外,還有什么別的方法锌半?
除了使用 FTWRL 外禽车,還可以使用命令 set global readonly=true 設(shè)置數(shù)據(jù)庫為只讀。
FTWRL 和 set global readonly=true 有什么區(qū)別刊殉?
FTWRL 和 set global readonly=true 都是設(shè)置整個數(shù)據(jù)庫為只讀狀態(tài)殉摔,但他們最大的區(qū)別就是,當(dāng)執(zhí)行 FTWRL
的客戶端斷開之后记焊,整個數(shù)據(jù)庫會取消只讀逸月,而 set global readonly=true 會一直讓數(shù)據(jù)處于只讀狀態(tài)。
如何實(shí)現(xiàn)表鎖遍膜?
MySQL 里標(biāo)記鎖有兩種:表級鎖碗硬、元數(shù)據(jù)鎖(meta data lock)簡稱 MDL。表鎖的語法是 lock tables t read/write瓢颅。
可以用 unlock tables 主動釋放鎖恩尾,也可以在客戶端斷開的時候自動釋放。lock tables
語法除了會限制別的線程的讀寫外挽懦,也限定了本線程接下來的操作對象翰意。
對于 InnoDB 這種支持行鎖的引擎,一般不使用 lock tables 命令來控制并發(fā)信柿,畢竟鎖住整個表的影響面還是太大冀偶。
MDL:不需要顯式使用,在訪問一個表的時候會被自動加上渔嚷。
MDL 的作用:保證讀寫的正確性蔫磨。
在對一個表做增刪改查操作的時候,加 MDL 讀鎖圃伶;當(dāng)要對表做結(jié)構(gòu)變更操作的時候堤如,加 MDL 寫鎖。
讀鎖之間不互斥窒朋,讀寫鎖之間搀罢,寫鎖之間是互斥的,用來保證變更表結(jié)構(gòu)操作的安全性侥猩。
MDL 會直到事務(wù)提交才會釋放榔至,在做表結(jié)構(gòu)變更的時候,一定要小心不要導(dǎo)致鎖住線上查詢和更新欺劳。
悲觀鎖和樂觀鎖有什么區(qū)別唧取?
顧名思義铅鲤,就是很悲觀,每次去拿數(shù)據(jù)的時候都認(rèn)為別人會修改枫弟,所以每次在拿數(shù)據(jù)的時候都會上鎖邢享,這樣別人想拿這個數(shù)據(jù)就會 block
直到它拿到鎖。正因?yàn)槿绱说^鎖需要耗費(fèi)較多的時間骇塘,另外與樂觀鎖相對應(yīng)的,悲觀鎖是由數(shù)據(jù)庫自己實(shí)現(xiàn)了的韩容,要用的時候款违,我們直接調(diào)用數(shù)據(jù)庫的相關(guān)語句就可以了。
說到這里群凶,由悲觀鎖涉及到的另外兩個鎖概念就出來了插爹,它們就是共享鎖與排它鎖。共享鎖和排它鎖是悲觀鎖的不同的實(shí)現(xiàn)请梢,它倆都屬于悲觀鎖的范疇递惋。
樂觀鎖是用數(shù)據(jù)版本(Version)記錄機(jī)制實(shí)現(xiàn),這是樂觀鎖最常用的一種實(shí)現(xiàn)方式溢陪。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個版本標(biāo)識睛廊,一般是通過為數(shù)據(jù)庫表增加一個數(shù)字類型的
version 字段來實(shí)現(xiàn)形真。當(dāng)讀取數(shù)據(jù)時,將 version 字段的值一同讀出超全,數(shù)據(jù)每更新一次咆霜,對此 version 值加
1。當(dāng)我們提交更新的時候嘶朱,判斷數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息與第一次取出來的version值進(jìn)行比對蛾坯,如果數(shù)據(jù)庫表當(dāng)前版本號與第一次取出來的 version
值相等,則予以更新疏遏,否則認(rèn)為是過期數(shù)據(jù)脉课。
比如: 1、數(shù)據(jù)庫表三個字段财异,分別是id倘零、value、version select id,value,version from t where id=#{id}
2戳寸、每次更新表中的value字段時呈驶,為了防止發(fā)生沖突,需要這樣操作
update t
set value=2,version=version+1
where id=#{id} and version=#{version}
樂觀鎖有什么優(yōu)點(diǎn)和缺點(diǎn)疫鹊?
因?yàn)闆]有加鎖所以樂觀鎖的優(yōu)點(diǎn)就是執(zhí)行性能高袖瞻。它的缺點(diǎn)就是有可能產(chǎn)生 ABA 的問題司致,ABA 問題指的是有一個變量 V 初次讀取的時候是 A
值,并且在準(zhǔn)備賦值的時候檢查到它仍然是 A 值聋迎,會誤以為沒有被修改會正常的執(zhí)行修改操作脂矫,實(shí)際上這段時間它的值可能被改了其他值,之后又改回為 A
值砌庄,這個問題被稱為 ABA 問題羹唠。
InnoDB 存儲引擎有幾種鎖算法?
- Record Lock — 單個行記錄上的鎖娄昆;
- Gap Lock — 間隙鎖佩微,鎖定一個范圍,不包括記錄本身萌焰;
- Next-Key Lock — 鎖定一個范圍哺眯,包括記錄本身。
InnoDB 如何實(shí)現(xiàn)行鎖扒俯?
行級鎖是 MySQL 中粒度最小的一種鎖奶卓,他能大大減少數(shù)據(jù)庫操作的沖突。
INNODB 的行級鎖有共享鎖(S LOCK)和排他鎖(X
LOCK)兩種撼玄。共享鎖允許事物讀一行記錄夺姑,不允許任何線程對該行記錄進(jìn)行修改。排他鎖允許當(dāng)前事物刪除或更新一行記錄掌猛,其他線程不能操作該記錄盏浙。
共享鎖:SELECT ... LOCK IN SHARE MODE,MySQL
會對查詢結(jié)果集中每行都添加共享鎖荔茬,前提是當(dāng)前線程沒有對該結(jié)果集中的任何行使用排他鎖废膘,否則申請會阻塞。
排他鎖:select * from t where id=1 for update慕蔚,其中 id 字段必須有索引丐黄,MySQL
會對查詢結(jié)果集中每行都添加排他鎖,在事物操作中孔飒,任何對記錄的更新與刪除操作會自動加上排他鎖灌闺。前提是當(dāng)前沒有線程對該結(jié)果集中的任何行使用排他鎖或共享鎖,否則申請會阻塞坏瞄。
優(yōu)化鎖方面你有什么建議菩鲜?
- 盡量使用較低的隔離級別。
- 精心設(shè)計索引惦积, 并盡量使用索引訪問數(shù)據(jù)接校, 使加鎖更精確, 從而減少鎖沖突的機(jī)會。
- 選擇合理的事務(wù)大小蛛勉,小事務(wù)發(fā)生鎖沖突的幾率也更小鹿寻。
- 給記錄集顯示加鎖時,最好一次性請求足夠級別的鎖诽凌。比如要修改數(shù)據(jù)的話毡熏,最好直接申請排他鎖,而不是先申請共享鎖侣诵,修改時再請求排他鎖痢法,這樣容易產(chǎn)生死鎖。
- 不同的程序訪問一組表時杜顺,應(yīng)盡量約定以相同的順序訪問各表财搁,對一個表而言,盡可能以固定的順序存取表中的行躬络。這樣可以大大減少死鎖的機(jī)會尖奔。
- 盡量用相等條件訪問數(shù)據(jù),這樣可以避免間隙鎖對并發(fā)插入的影響穷当。
- 不要申請超過實(shí)際需要的鎖級別提茁。
- 除非必須,查詢時不要顯示加鎖馁菜。 MySQL 的 MVCC 可以實(shí)現(xiàn)事務(wù)中的查詢不用加鎖茴扁,優(yōu)化事務(wù)性能;MVCC 只在 COMMITTED READ(讀提交)和 REPEATABLE READ(可重復(fù)讀)兩種隔離級別下工作汪疮。
- 對于一些特定的事務(wù)峭火,可以使用表鎖來提高處理速度或減少死鎖的可能。