innodb存储引擎 - 锁
MySQL技術(shù)內(nèi)幕:Innodb存儲引擎
(間隙鎖目前理解的還不是很透徹,后面索引看完了再過來回顧一下間隙鎖)
第六章 鎖
一、Innodb存儲引擎中的鎖
1.鎖是數(shù)據(jù)庫區(qū)別于文件系統(tǒng)的一個(gè)關(guān)鍵特性,
2.兩種標(biāo)準(zhǔn)的行級鎖:
- 共享鎖(S Lock):允許事務(wù)讀一行數(shù)據(jù)
- 排它鎖(X Lock):允許事務(wù)刪除或更新一行數(shù)據(jù)
? S鎖與S鎖兼容,與X鎖不兼容:也就是如果事務(wù)t1獲取了行r的共享鎖,那么事務(wù)t2也想獲取行r的共享鎖是可以獲取到的(這種情況成為鎖兼容),但是如果事務(wù)t3想獲取行r的排它鎖是不能獲取到的,必須釋放t1、t2釋放行r上的共享鎖(這種情況成為鎖不兼容)。
? X鎖與任何鎖都不兼容。
? S鎖與X鎖都是行鎖,兼容指的是對于同一行(row)數(shù)據(jù)來說。
? 表:排它鎖與共享鎖的兼容性
| X | 不兼容 | 不兼容 |
| S | 不兼容 | 兼容 |
Innodb支持多粒度鎖定,這種鎖定允許事務(wù)在行級鎖和表級鎖同時(shí)存在,為了支持在不同粒度上進(jìn)行加鎖操作,Innodb支持一種額外的鎖方式,叫做意向鎖。
3.意向鎖:
意向鎖的含義,在innodb中如果對表加了意向鎖,說明表中的行在加鎖的狀態(tài),對任意行加鎖前必須先對他的表加上意向鎖,
意向鎖分為:
- 意向共享鎖:事務(wù)想獲得一張表中某幾行的共享鎖
- 意向排它鎖:事務(wù)想獲得一張表中某幾行的排它鎖
由于innodb存儲引擎支持的行級鎖,因此意向鎖其實(shí)不會阻塞除全表掃描以外的任何請求。故表級意向鎖與表級鎖的兼容性如表
| IS | 兼容 | 兼容 | 兼容 | 不兼容 |
| IX | 兼容 | 兼容 | 不兼容 | 不兼容 |
| S | 兼容 | 不兼容 | 兼容 | 不兼容 |
| X | 不兼容 | 不兼容 | 不兼容 | 不兼容 |
PS:上述表格中的IS、IX、S、X都表示的是表級鎖,S、X并不是書上 所說的表級鎖。
4.一致性非鎖定讀(和隔離級別有關(guān))
如果讀取的行正在執(zhí)行delete或者update操作,這時(shí)讀取操作不會因此去等待行上鎖的釋放,相反,Innodb會去讀取行的一個(gè)快照數(shù)據(jù)。之所以成為非鎖定讀,是因?yàn)椴恍枰却猩系腦鎖釋放。
快照數(shù)據(jù):是指改行之前的版本的數(shù)據(jù),該實(shí)現(xiàn)是通過undo段來完成的,而undo用來在事務(wù)回滾數(shù)據(jù)。因此快照本身并沒有額外的開銷。
因此一致性非鎖定讀提高了并發(fā)性,Innodb存儲引擎是默認(rèn)的讀取方式,即讀取不會占用和等待表上的鎖,但是在不同的隔離級別下,讀取的方式是不同的,并不是每個(gè)事物的隔離級別都采用一致性非鎖定讀的,并且即使采用一致性非鎖定度讀取的快照副本也是不一樣的。
在事務(wù)的隔離級別Read Committed(讀已提交)和Repeatable Read(可重復(fù)度)下,Innodb采用一致性非鎖定讀;Read Committed 下是讀取被鎖定行的最新一份的快照數(shù)據(jù),而Repeatable Read下是讀取事務(wù)開始時(shí)的行數(shù)據(jù)版本。
例子:Read Committed下:事務(wù)1開啟查詢id=1,事務(wù)二開啟將id=1的值改變?yōu)榱薸d=2;事務(wù)1再一次讀id=1,獲取的結(jié)果為Empty,因?yàn)樽x已提交是讀取最新一份的快照數(shù)據(jù)。
Repeatable Read下:事務(wù)1開啟查詢id=1,事務(wù)二開啟將id=1的值改變?yōu)榱薸d=2;事務(wù)1再一次讀id=1,獲取的結(jié)果是id=1,因?yàn)榭芍貜?fù)度是會讀取事務(wù)開啟時(shí)的快照副本的數(shù)據(jù)。
ps:查看當(dāng)前的隔離級別:select @@tx_isolation;
? 更改事務(wù)的隔離級別:set [ global | session ] transaction isolation level Read uncommitted | Read committed | Repeatable | Serializable; (global | session :全局(已存在的不受影響)|當(dāng)前窗口)
5.一致性鎖定讀
在某些情況下,用戶需要顯式地對數(shù)據(jù)庫讀取操作進(jìn)行加鎖來保證數(shù)據(jù)邏輯的一致性,這就要求數(shù)據(jù)庫支持對讀操作的加鎖語句,即便是只讀。Innodb存儲引擎對于select語句支持兩種一致性鎖定讀操作:
- Select … For Update
- Select … Lock In Share Mode
Select … for update 對讀取的行記錄加一個(gè)X鎖,其他事物不能對已鎖定的行加任何鎖。
Select … Lock In Share Mode 對讀取的行記錄加一個(gè)S鎖,其他事物可以向被鎖定的行加S鎖,但如果加X鎖,則會被阻塞;
對于一致性非鎖定讀即使讀取的行已經(jīng)加了select … for update也是可以讀取的,因?yàn)樗x取的快照數(shù)據(jù)。
另外一致性鎖定讀Select … For Update、Select … Lock In Share Mode必須在事務(wù)中使用才有用,當(dāng)事務(wù)提交了,鎖也就被釋放了。
6.外鍵和鎖
外鍵主要用于完整的約束性檢查,在Innodb中對于一個(gè)外鍵列,如果沒有顯式地創(chuàng)建這個(gè)列的索引,Innodb存儲引擎就會對其加一個(gè)索引,因?yàn)檫@樣可以避免表鎖。
對于外鍵值的插入或更新,首先需要查詢父表中的記錄,即select父表。但是對于父表Select操作,不是使用的一致性非鎖定讀的方式,因?yàn)檫@樣會導(dǎo)致數(shù)據(jù)的不一致的問題,因此這時(shí)使用的是Select … Lock In Share Mode 方式,即主動對父表加S鎖,如果這時(shí)父表已經(jīng)被上了X鎖,子表的操作會被阻塞。
例子:假設(shè)父表id與子表pid關(guān)聯(lián),事務(wù)1刪除父表中id=1的行不提交會對id=1的行加X鎖,事務(wù)2要向子表中插入數(shù)據(jù)pid=1的數(shù)據(jù),首先要Select父表id=1就會對id=1的行加S鎖,X鎖是排它鎖所以Select操作被阻塞,所以子表插入被阻塞。
鎖的算法
行鎖的三種算法
- Record Lock:單個(gè)行記錄上的鎖
- Gap Lock:間隙鎖,鎖定一個(gè)范圍,但不包含記錄本身
- Next-Key Lock:Gap Lock+Record Lock,鎖定一個(gè)范圍并包含記錄本身
Record Lock:總是會去鎖住索引記錄,如果Innodb存儲引擎表在建立的時(shí)候沒有設(shè)置任何一個(gè)索引,那么這時(shí)Innodb存儲引擎會使用隱式地主鍵來進(jìn)行鎖定。
Next-Key Lock:是結(jié)合了Gap Lock 和 Record Lock的一種鎖定算法,在Next-Key Lock算法下,Innodb對于行的查詢都采用這種鎖定算法,例如一個(gè)索引有10,11,13,和20四個(gè)值,那么該索引可能被Next-Key Locking的區(qū)間為
(負(fù)無窮 - 10 ]
(10 - 11]
(11 - 13]
(13 - 20]
(20 - 正無窮)
除了Next-key Locking 還有previous-key locking,使用previous-key locking鎖住的區(qū)間為
(負(fù)無窮 - 10 )
[10 - 11)
[11 - 13)
[13 - 20)
[20 - 正無窮)
當(dāng)查詢的索引含有唯一屬性時(shí),Innodb存儲引擎會對Next-Key locking進(jìn)行優(yōu)化,將其降級為Record Lock,即僅鎖住索引本身,而不是范圍。
鎖引發(fā)的問題:
臟讀:事務(wù)讀取到了其他事物未提交的數(shù)據(jù),違反了事務(wù)的隔離性。
不可重復(fù)讀:事務(wù)多次讀取到的數(shù)據(jù)不一樣,事務(wù)1第二次讀取的數(shù)據(jù)是其他事物DML操作后提交的數(shù)據(jù),造成了同一個(gè)語句兩次讀取的數(shù)據(jù)不一致。(與臟讀的區(qū)別是不可重復(fù)讀讀取的數(shù)據(jù)是事務(wù)提交后的,臟讀讀取的是事務(wù)未提交的數(shù)據(jù))
幻讀:在可重復(fù)度的隔離級別下:事務(wù)使用當(dāng)前讀(for update,直接讀讀取的是開啟時(shí)的undo快照數(shù)據(jù))后一次查詢查到了前一次沒有查到的行,造成了幻讀現(xiàn)象,使用間隙鎖解決。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的innodb存储引擎 - 锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中发生数据丢失_如何防止Redis脑裂导
- 下一篇: 给台积电28nm芯片厂补贴240亿元 专