MySQL鎖概述
相對其他數(shù)據(jù)庫而言,MySQL的鎖機(jī)制比較簡單,其最顯著的特點(diǎn)是不同的存儲(chǔ)引擎支持不同的鎖機(jī)制。比如,MyISAM和MEMORY存儲(chǔ)引擎采用的是表級(jí)鎖(table-level locking);BDB存儲(chǔ)引擎采用的是頁面鎖(page-level locking),但也支持表級(jí)鎖;InnoDB存儲(chǔ)引擎既支持行級(jí)鎖(row-level locking),也支持表級(jí)鎖,但默認(rèn)情況下是采用行級(jí)鎖。
MySQL這3種鎖的特性可大致歸納如下。
開銷、加鎖速度、死鎖、粒度、并發(fā)性能
l???????? 表級(jí)鎖:開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
l???????? 行級(jí)鎖:開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
l???????? 頁面鎖:開銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。
MySQL表級(jí)鎖的鎖模式
MySQL的表級(jí)鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨(dú)占寫鎖(Table Write Lock)。
|模式 |讀鎖 ?|寫鎖 ?|
| ------------- |:-------------:| -----:|
|讀鎖 ? ?|是 ?|否 |
|讀鎖? ? | 否? |否 |
可見,對MyISAM表的讀操作,不會(huì)阻塞其他用戶對同一表的讀請求,但會(huì)阻塞對同一表的寫請求。
如何加表鎖
MyISAM在執(zhí)行查詢語句(SELECT)前,會(huì)自動(dòng)給涉及的所有表加讀鎖,在執(zhí)行更新操作(UPDATE、DELETE、INSERT等)前,會(huì)自動(dòng)給涉及的表加寫鎖,這個(gè)過程并不需要用戶干預(yù)。
并發(fā)插入(Concurrent Inserts)
上文提到過MyISAM表的讀和寫是串行的,但這是就總體而言的。在一定條件下,MyISAM表也支持查詢和插入操作的并發(fā)進(jìn)行。 MyISAM存儲(chǔ)引擎有一個(gè)系統(tǒng)變量concurrent_insert,專門用以控制其并發(fā)插入的行為,其值分別可以為0、1或2。 l? ? ? ? 當(dāng)concurrent_insert設(shè)置為0時(shí),不允許并發(fā)插入。 l? ? ? ? 當(dāng)concurrent_insert設(shè)置為1時(shí),如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個(gè)進(jìn)程讀表的同時(shí),另一個(gè)進(jìn)程從表尾插入記錄。這也是MySQL的默認(rèn)設(shè)置。 l? ? ? ? 當(dāng)concurrent_insert設(shè)置為2時(shí),無論MyISAM表中有沒有空洞,都允許在表尾并發(fā)插入記錄。
MyISAM的鎖調(diào)度
前面講過,MyISAM存儲(chǔ)引擎的讀鎖和寫鎖是互斥的,讀寫操作是串行的。那么,一個(gè)進(jìn)程請求某個(gè) MyISAM表的讀鎖,同時(shí)另一個(gè)進(jìn)程也請求同一表的寫鎖,MySQL如何處理呢?答案是寫進(jìn)程先獲得鎖。不僅如此,即使讀請求先到鎖等待隊(duì)列,寫請求后到,寫鎖也會(huì)插到讀鎖請求之前!這是因?yàn)镸ySQL認(rèn)為寫請求一般比讀請求要重要。這也正是MyISAM表不太適合于有大量更新操作和查詢操作應(yīng)用的原因,因?yàn)?,大量的更新操作?huì)造成查詢操作很難獲得讀鎖,從而可能永遠(yuǎn)阻塞。這種情況有時(shí)可能會(huì)變得非常糟糕!
InnoDB的行鎖模式及加鎖方法
InnoDB實(shí)現(xiàn)了以下兩種類型的行鎖。
l? 共享鎖(S):允許事務(wù)去讀一行,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖。
l? 排他鎖(X):允許獲得排他鎖的事務(wù)更新數(shù)據(jù),阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和排他寫鎖。
| |共享鎖 |排他鎖 |
| ------------- |:-------------:| -----:|
|共享鎖 ? | 是 ?|否 |
|排他鎖 ? 否? |否 |
另外,為了允許行鎖和表鎖共存,實(shí)現(xiàn)多粒度鎖機(jī)制,InnoDB還有兩種內(nèi)部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖。
l? 意向共享鎖(IS):事務(wù)打算給數(shù)據(jù)行加行共享鎖,事務(wù)在給一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖。
l? 意向排他鎖(IX):事務(wù)打算給數(shù)據(jù)行加行排他鎖,事務(wù)在給一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖。
表20-6? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? InnoDB行鎖模式兼容性列表
|請求鎖模式
是否兼容
當(dāng)前鎖模式 |X |IX |S |IS|
| ------------- |:-------------:| -----:|-----:|
|X |沖突 |沖突 |沖突 |沖突 |
|IX |沖突 |兼容 |沖突 |兼容 |
|S |沖突 |沖突 |兼容 |兼容 |
|IS |沖突 |兼容 |兼容 |兼容 |
如果一個(gè)事務(wù)請求的鎖模式與當(dāng)前的鎖兼容,InnoDB就將請求的鎖授予該事務(wù);反之,如果兩者不兼容,該事務(wù)就要等待鎖釋放。
意向鎖是InnoDB自動(dòng)加的,不需用戶干預(yù)。對于UPDATE、DELETE和INSERT語句,InnoDB會(huì)自動(dòng)給涉及數(shù)據(jù)集加排他鎖(X);對于普通SELECT語句,InnoDB不會(huì)加任何鎖;事務(wù)可以通過以下語句顯示給記錄集加共享鎖或排他鎖。
?? 共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。
?? 排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE。
用SELECT ... IN SHARE MODE獲得共享鎖,主要用在需要數(shù)據(jù)依存關(guān)系時(shí)來確認(rèn)某行記錄是否存在,并確保沒有人對這個(gè)記錄進(jìn)行UPDATE或者DELETE操作。但是如果當(dāng)前事務(wù)也需要對該記錄進(jìn)行更新操作,則很有可能造成死鎖,對于鎖定行記錄后需要進(jìn)行更新操作的應(yīng)用,應(yīng)該使用SELECT... FOR UPDATE方式獲得排他鎖。
InnoDB行鎖實(shí)現(xiàn)方式
InnoDB行鎖是通過給索引上的索引項(xiàng)加鎖來實(shí)現(xiàn)的,這一點(diǎn)MySQL與Oracle不同,后者是通過在數(shù)據(jù)塊中對相應(yīng)數(shù)據(jù)行加鎖來實(shí)現(xiàn)的。InnoDB這種行鎖實(shí)現(xiàn)特點(diǎn)意味著:只有通過索引條件檢索數(shù)據(jù),InnoDB才使用行級(jí)鎖,否則,InnoDB將使用表鎖!
間隙鎖(Next-Key鎖)
當(dāng)我們用范圍條件而不是相等條件檢索數(shù)據(jù),并請求共享或排他鎖時(shí),InnoDB會(huì)給符合條件的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖;對于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做“間隙(GAP)”,InnoDB也會(huì)對這個(gè)“間隙”加鎖,這種鎖機(jī)制就是所謂的間隙鎖(Next-Key鎖)。
舉例來說,假如emp表中只有101條記錄,其empid的值分別是 1,2,...,100,101,下面的SQL:
Select * from ?emp where empid > 100 for update;
是一個(gè)范圍條件的檢索,InnoDB不僅會(huì)對符合條件的empid值為101的記錄加鎖,也會(huì)對empid大于101(這些記錄并不存在)的“間隙”加鎖。
InnoDB使用間隙鎖的目的,一方面是為了防止幻讀,以滿足相關(guān)隔離級(jí)別的要求,對于上面的例子,要是不使用間隙鎖,如果其他事務(wù)插入了empid大于100的任何記錄,那么本事務(wù)如果再次執(zhí)行上述語句,就會(huì)發(fā)生幻讀;另外一方面,是為了滿足其恢復(fù)和復(fù)制的需要。有關(guān)其恢復(fù)和復(fù)制對鎖機(jī)制的影響,以及不同隔離級(jí)別下InnoDB使用間隙鎖的情況,在后續(xù)的章節(jié)中會(huì)做進(jìn)一步介紹。
參考資料:
1.MySQL詳解--鎖 - 上善若水,水善利萬物而不爭。 - CSDN博客 http://blog.csdn.net/xifeijian/article/details/20313977
2.《高性能MySQL》
3.《MySQL必知必會(huì)》
