數(shù)據(jù)庫(kù)鎖
- 表鎖:開(kāi)銷(xiāo)小大诸,加鎖快;不會(huì)出現(xiàn)死鎖贯卦;鎖定力度大,發(fā)生鎖沖突概率高焙贷,并發(fā)度最低
- 行鎖:開(kāi)銷(xiāo)大撵割,加鎖慢;會(huì)出現(xiàn)死鎖辙芍;鎖定粒度小啡彬,發(fā)生鎖沖突的概率低羹与,并發(fā)度高
- InnoDB行鎖和表鎖都支持!InnoDB只有通過(guò)索引條件檢索數(shù)據(jù)才使用行級(jí)鎖
- MyISAM只支持表鎖庶灿!
MyISAM表級(jí)鎖
MySQL 的表級(jí)鎖有兩種模式:表共享讀鎖纵搁、表獨(dú)占寫(xiě)鎖
讀讀不阻塞,讀寫(xiě)阻塞往踢,寫(xiě)寫(xiě)阻塞
讀鎖和寫(xiě)鎖是互斥的腾誉,讀寫(xiě)操作是串行
對(duì) MyISAM 表的讀操作,不會(huì)阻塞其他用戶對(duì)同一表的讀請(qǐng)求峻呕,但會(huì)阻塞對(duì)同一表的寫(xiě)請(qǐng)求利职;對(duì) MyISAM 表的寫(xiě)操作,則會(huì)阻塞其他用戶對(duì)同一表的讀和寫(xiě)操作瘦癌。當(dāng)一個(gè)線程獲得對(duì)一個(gè)表的寫(xiě)鎖后猪贪,只有持有鎖的線程可以對(duì)表進(jìn)行更新操作。其他線程的讀讯私、寫(xiě)操作都會(huì)等待热押,直到鎖被釋放為止。
session_1 | session_2 |
---|---|
獲得text表的鎖定: mysql> lock table text write; |
略 |
當(dāng)前 session 對(duì)text表的查詢斤寇、更新桶癣、插入操作都可以執(zhí)行 | session2對(duì)于text表的查詢、更新抡驼、插入操作都得阻塞等待 |
釋放鎖: unlock tables; |
等待 |
session_2的操作得到執(zhí)行 |
如何給MyISAM加表鎖
MyISAM 在執(zhí)行查詢語(yǔ)句(SELECT)前鬼廓,會(huì)自動(dòng)給涉及的所有表加讀鎖,在執(zhí)行更新操作(UPDATE致盟、DELETE碎税、INSERT 等)前,會(huì)自動(dòng)給涉及的表加寫(xiě)鎖馏锡,這個(gè)過(guò)程并不需要用戶干預(yù)雷蹂,因此,用戶一般不需要直接用 LOCK TABLE 命令給 MyISAM 表顯式加鎖杯道。
但有些特殊需求下需要我們手動(dòng)加表鎖匪煌。舉個(gè)例子:例如訂單表記錄了訂單的總金額,訂單詳細(xì)表記錄了訂單中各個(gè)商品的價(jià)格党巾,現(xiàn)在需要比對(duì)訂單總金額跟訂單詳細(xì)表金額的總價(jià)是否正確萎庭。
select sum(total) from orders;
select sum(subtotal) from order_detail;
比對(duì) toatal 和 total_deail
這時(shí)候就需要手動(dòng)將order,order_detail手動(dòng)加鎖,不然查詢時(shí)又有新的記錄插入會(huì)導(dǎo)致比對(duì)不一致齿拂。
Lock tables orders read local, order_detail read local;
Select sum(total) from orders;
Select sum(subtotal) from order_detail;
Unlock tables;
注意點(diǎn):
- 在執(zhí)行 LOCK TABLES 后驳规,只能訪問(wèn)顯式加鎖的這些表,不能訪問(wèn)未加鎖的表
- 如果加的是讀鎖署海,那么只能執(zhí)行查詢操作吗购,而不能執(zhí)行更新操作
- 寫(xiě)鎖和讀鎖優(yōu)先級(jí)的問(wèn)題是可以通過(guò)參數(shù)調(diào)節(jié)的:max_write_lock_count和low-priority-updates
- MyISAM可以支持查詢和插入操作的并發(fā)進(jìn)行医男。可以通過(guò)系統(tǒng)變量concurrent_insert來(lái)指定哪種模式捻勉,在MyISAM中它默認(rèn)是:如果MyISAM表中沒(méi)有空洞(即表的中間沒(méi)有被刪除的行)镀梭,MyISAM允許在一個(gè)進(jìn)程讀表的同時(shí),另一個(gè)進(jìn)程從表尾插入記錄踱启。
MyISAM 的鎖調(diào)度
MyISAM 存儲(chǔ)引擎的讀鎖和寫(xiě)鎖是互斥的报账,讀寫(xiě)操作是串行的。那么禽捆,一個(gè)進(jìn)程請(qǐng)求某個(gè) MyISAM 表的讀鎖笙什,同時(shí)另一個(gè)進(jìn)程也請(qǐng)求同一表的寫(xiě)鎖,MySQL 如何處理呢胚想?
寫(xiě)進(jìn)程先獲得鎖琐凭。不僅如此,即使讀請(qǐng)求先到鎖等待隊(duì)列浊服,寫(xiě)請(qǐng)求后到统屈,寫(xiě)鎖也會(huì)插到讀鎖請(qǐng)求之前
Innodb行鎖
InnoDB實(shí)現(xiàn)了以下兩種類(lèi)型的行鎖
- 共享鎖(S鎖):允許一個(gè)事務(wù)去讀一行,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖
(也叫做讀鎖:讀鎖是共享的牙躺,多個(gè)客戶可以同時(shí)讀取同一個(gè)資源愁憔,但不允許其他客戶修改) - 排他鎖(X鎖) :允許獲得排他鎖的事務(wù)更新數(shù)據(jù),阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和排他寫(xiě)鎖
(也叫做寫(xiě)鎖:寫(xiě)鎖是排他的孽拷,寫(xiě)鎖會(huì)阻塞其他的寫(xiě)鎖和讀鎖)
另外吨掌,為了允許行鎖和表鎖共存,實(shí)現(xiàn)多粒度鎖機(jī)制脓恕,InnoDB 還有兩種內(nèi)部使用的意向鎖(Intention Locks)膜宋,這兩種意向鎖都是表鎖
- 意向共享鎖(IS):事務(wù)打算給數(shù)據(jù)行加行共享鎖,事務(wù)在給一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的 IS 鎖
-
意向排他鎖(IX):事務(wù)打算給數(shù)據(jù)行加行排他鎖炼幔,事務(wù)在給一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的 IX 鎖
image.png
意向鎖是 InnoDB 自動(dòng)加的秋茫,不需用戶干預(yù)。對(duì)于 UPDATE乃秀、DELETE 和 INSERT 語(yǔ)句肛著,InnoDB會(huì)自動(dòng)給涉及數(shù)據(jù)集加排他鎖(X);對(duì)于普通 SELECT 語(yǔ)句跺讯,InnoDB 不會(huì)加任何鎖枢贿;事務(wù)可以通過(guò)以下語(yǔ)句顯示給記錄集加共享鎖或排他鎖:
- 共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
- 排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE
只有通過(guò)索引條件檢索數(shù)據(jù),InnoDB 才使用行級(jí)鎖刀脏,否則萨咕,InnoDB 將使用表鎖
session1 | session2 |
---|---|
mysql> select * from tab_no_index where id = 1 for update; | |
mysql> select * from tab_no_index where id = 2 for update; 阻塞等待 |
這里由于tab_on_index表沒(méi)有加索引,所以即使是為id=1的加鎖火本,也是用到的不是行鎖而是表鎖危队,所以導(dǎo)致session2查詢時(shí)阻塞等待
由于 MySQL 的行鎖是針對(duì)索引加的鎖,不是針對(duì)記錄加的鎖钙畔,所以雖然是訪問(wèn)不同行的記錄茫陆,但是如果是使用相同的索引鍵,是會(huì)出現(xiàn)鎖沖突的擎析。
當(dāng)表有多個(gè)索引的時(shí)候簿盅,不同的事務(wù)可以使用不同的索引鎖定不同的行,另外揍魂,不論是使用主鍵索引桨醋、唯一索引或普通索引,InnoDB 都會(huì)使用行鎖來(lái)對(duì)數(shù)據(jù)加鎖
間隙鎖
當(dāng)我們用范圍條件而不是相等條件檢索數(shù)據(jù)现斋,并請(qǐng)求共享或排他鎖時(shí)喜最,InnoDB 會(huì)給符合條件的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖;對(duì)于鍵值在條件范圍內(nèi)但并不存在的記錄庄蹋,叫做“間隙(GAP)”瞬内,InnoDB 也會(huì)對(duì)這個(gè)“間隙”加鎖,這種鎖機(jī)制就是所謂的間隙鎖(Next-Key 鎖)限书。