mysql innodb存儲引擎支持事務(wù)遂鹊,是mysql的默認(rèn)存儲引擎振乏。
數(shù)據(jù)庫事務(wù)
事務(wù)是由一組sql語句組成的邏輯單元,完成特定的任務(wù)秉扑。事務(wù)有四個基本屬性慧邮,通常稱為ACID:
Atomic:原子性,組成事務(wù)的sql語句要么全部執(zhí)行舟陆,要么全部不執(zhí)行
Consitensy:事務(wù)完成后误澳,數(shù)據(jù)庫處于一致性狀態(tài)。事務(wù)需經(jīng)過良好的設(shè)計秦躯,才能讓數(shù)據(jù)保持在一致狀態(tài)
Isolation:隔離性忆谓,并發(fā)事務(wù)不受彼此干擾,事務(wù)處理的中間狀態(tài)對外部不可見
durable:持久性踱承,一旦事務(wù)執(zhí)行完成倡缠,對于數(shù)據(jù)的修改是永久性的,即使出現(xiàn)故障也能夠保持
innodb支持事務(wù)茎活,是innodb區(qū)別于其他存儲引擎最重要的一點昙沦,除此之外還有行鎖,這也是mysql如此流行的原因载荔。
并發(fā)事務(wù)的常見問題
對于并發(fā)事務(wù)來說盾饮,能大大提高數(shù)據(jù)庫的性能以及吞吐量,但是并發(fā)事務(wù)處理身辨,通常存在如下問題:
Lost Update: 當(dāng)兩個事務(wù)并發(fā)修改同一行時丐谋,如果是基于原值基礎(chǔ)上的更新,有可能后寫入的覆蓋了之前一次的寫入
臟讀: 某個事務(wù)讀取到了其他事務(wù)未提交的值煌珊,稱之為臟讀
不可重復(fù)讀:在同一個事務(wù)里号俐,針對相同的查詢語句,返回的數(shù)據(jù)已經(jīng)發(fā)生了改變定庵,或者被刪除吏饿,稱為不可重復(fù)讀
幻讀:在同一個事務(wù)里,按照相同的查詢條件蔬浙,后一次查詢返回了比前一次查詢更多的結(jié)果猪落,發(fā)現(xiàn)其他事務(wù)插入的新數(shù)據(jù),稱之為幻讀
數(shù)據(jù)庫隔離級別
為了解決并發(fā)事務(wù)的問題畴博,就有了數(shù)據(jù)庫的隔離級別笨忌,不同的隔離級別,解決不同的問題俱病。通常有RU官疲,RC袱结,RR,Serializable四種
RU: read uncommited途凫,讀未提交
RC:read commited 讀已提交
RR:repeatable read 可重復(fù)讀
serializable: 串行化
事務(wù)的隔離性是通過鎖來實現(xiàn)的垢夹,mysql事務(wù)的默認(rèn)隔離級別是RR
InnoDB使用的鎖
為了支持事務(wù),以及不同的隔離級別维费,innodb提供了如下類型的鎖:
1.共享鎖果元,排他鎖(S鎖,X鎖)S通常指的是讀鎖犀盟,X是寫鎖而晒。有一點需要提出的是,S鎖且蓬,X鎖不是具體的鎖欣硼,而是鎖的模式,用來'修飾'其他的鎖
2.意向鎖 意向鎖是表鎖恶阴,Intention Lock有兩種模式诈胜,意向共享鎖和意向排他鎖 簡稱IS和IX
3.Record Lock,記錄鎖冯事,記錄鎖也分為S鎖和X鎖
4.Gap Locks 間隙鎖焦匈,鎖住記錄的間隙,解決幻讀問題
5.Next-key Locks昵仅,鄰鍵鎖 = 行鎖+間隙鎖
6.插入意向鎖
7.自增鎖 自增列的鎖
共享鎖排他鎖
共享鎖(S鎖)和排他鎖(X鎖)的概念在許多編程語言中都出現(xiàn)過缓熟。先來描述一下這兩種鎖在MySQL中的影響結(jié)果:
如果一個事務(wù)對某一行數(shù)據(jù)加了S鎖,另一個事務(wù)還可以對相應(yīng)的行加S鎖摔笤,但是不能對相應(yīng)的行加X鎖够滑。
如果一個事務(wù)對某一行數(shù)據(jù)加了X鎖,另一個事務(wù)既不能對相應(yīng)的行加S鎖也不能加X鎖吕世。
行鎖彰触,間隙鎖,鄰鍵鎖
這三種鎖描述的都是鎖定范圍命辖,mysql官方文檔的定義如下:
記錄鎖:記錄鎖鎖定索引的一條記錄况毅,對于unique索引,鎖住唯一的一行尔艇,對于二級索引尔许,鎖定索引以及對應(yīng)的聚集索引
間隙鎖:間隙索引要么鎖住索引記錄中間的值,要么鎖住索引第一個索引記錄之前的值终娃,或者是最后一個索引之后的值
鄰鍵鎖:是索引記錄上的鎖和在索引記錄之前的間隙鎖的組合
在定義中味廊,都提到了索引記錄,為什么?行鎖和索引有什么關(guān)系呢毡们?其實迅皇,innodb是通過掃描索引來進(jìn)行加鎖操作,innodb會為他
遇到的每一個索引增加共享鎖或者排他鎖衙熔,因此記錄鎖也稱為索引記錄鎖。row-level lock其實就是index-record lock搅荞。行鎖其實是加到
相應(yīng)的索引記錄上的
這三種鎖的鎖定范圍不同红氯,逐漸擴(kuò)大,我們舉個例子來說明咕痛,假設(shè)表test中有索引列3痢甘,5,8茉贡,9塞栅,四個數(shù)組值,那對應(yīng)的鎖的鎖定范圍如下:
記錄鎖:鎖定范圍是單獨的索引記錄腔丧,也就是3,5,8,9這四行
間隙鎖:間隙鎖的鎖定范圍為行中間隙放椰,為(-∞,3),(3,5),(5,8)(8,9)
鄰鍵鎖:索引記錄和索引記錄前的間隙鎖,為(-∞,3],(3,5],(5,8](8,9]
對于間隙鎖愉粤,需要額外補充如下幾點:
1.間隙鎖阻止其他事務(wù)對間隙的并發(fā)插入砾医,這樣能有效的解決幻讀問題,因此不是所有事務(wù)隔離級別都支持間隙鎖
2.間隙鎖的作用只是阻止其他事務(wù)在間隙插入數(shù)據(jù)衣厘,不會阻止其他事務(wù)擁有想用的間隙鎖如蚜,除了insert語句,其他事務(wù)對同樣的行加
間隙鎖不會被阻塞
3.對于唯一索引的加鎖行為影暴,間隙鎖會失效错邦,只有指定的行鎖
mysql 5.7及之前,可以通過information_schema.innodb_locks查看事務(wù)的鎖情況型宙,但是只能看到阻塞事務(wù)的鎖撬呢,如果事務(wù)并未阻塞,在
該表中看不到事務(wù)的鎖情況早歇。mysql 8.0刪除了information_schema.innodb_locks倾芝,添加了performance_schema.data_locks,? 支持查看未阻塞場景下的對事務(wù)持有的鎖
innodb常用SQL語句的加鎖方式
上面已經(jīng)介紹了innodb的各種類型的鎖,那么不同的sql語句分別加了什么鎖呢箭跳?
鎖的作用是為了解決并發(fā)事務(wù)的控制問題的晨另。即兩個并發(fā)執(zhí)行的事務(wù),如果T1正在修改某些行谱姓,那么T2要并發(fā)讀取借尿、修改、刪除,插入滿足T1查詢條件的行時路翻,T2就必須被阻塞狈癞。這就是通過鎖來實現(xiàn)的。通常茂契,要么是T1在已存在的行上加index record lock排他鎖是的T2無法觸碰已存在的行蝶桶,以及T1在不存在的行上加gap lock是的T2無法插入新的滿足條件的行
加什么樣的鎖,與以下因素相關(guān):
1.數(shù)據(jù)庫的事務(wù)隔離級別
2.SQL是一致性非鎖定讀掉冶,還是DML真竖,或鎖定讀
3.SQL執(zhí)行是是否用到的索引,以及索引類型(主鍵索引厌小,唯一索引恢共,普通索引)
下面我們來分析下,不同的隔離級別下璧亚,使用不同的索引時讨韭,分別加什么鎖。
通常癣蟋,普通SELECT使用(快照讀)Snapshot Read透硝,無需加鎖。RU和Serializable兩個事務(wù)隔離級別我們不會用到梢薪。
事務(wù)隔離級別為RR模式:
如果使用非唯一索引進(jìn)行搜索或掃描蹬铺,則在鎖掃描的每一個索引記錄上都設(shè)置next-key lock。這里鎖掃描的每一個索引記錄是指當(dāng)掃描執(zhí)行計劃中所使用的的索引時秉撇,搜索遇到的每一條記錄甜攀,where條件是否排除掉某個數(shù)據(jù)行并沒有關(guān)系。innodb并不記得確切的where條件琐馆,innodb倔強(qiáng)的只認(rèn)其掃描的索引范圍规阀。
這個有點難以理解,對于mysql的執(zhí)行計劃只會選擇一個索引瘦麸,使用一個索引來進(jìn)行掃描谁撼。mysql執(zhí)行sql語句的流程是先由innodb引擎執(zhí)行索引掃描,然后把結(jié)果返回給mysql服務(wù)器滋饲,mysql服務(wù)器再對該索引條件之外的其他查詢條件進(jìn)行求值厉碟,從而得到最終結(jié)果集。而加鎖時只考慮innodb掃描的索引屠缭,非索引的where條件并不考慮箍鼓。當(dāng)然,mysql使用index_merge優(yōu)化時會同時使用多個索引的呵曹。
加的鎖一般是next key lock款咖,這種鎖不僅鎖住索引本身何暮,還鎖住了每一條索引記錄前面的間隙,從而阻止其他事務(wù)向索引記錄前面緊接著的間隙中插入記錄
由于innodb聚集索引的特性铐殃,以及普通索引的實現(xiàn)海洼,對普通索引加鎖時,會隱含的鎖住想用的聚集索引(主鍵索引)富腊。
如果使用了唯一索引的唯一搜索條件坏逢,innodb只在滿足條件的索引記錄上設(shè)置行鎖,不鎖定前面的間隙蟹肘。如果使用范圍搜索條件词疼,還是會加next key lock鎖住間隙
insert在插入的索引記錄上加X鎖,以及insert intention lock帘腹,不會阻止其他事務(wù)在插入的記錄前的間隙插入新的記錄,不同的事務(wù)可以向同一索引的間隙插入記錄而無需互相等待许饿。一個事務(wù)中insert語句會在插入的行的索引記錄上設(shè)置一把排他鎖阳欲,如果有鍵重復(fù)的錯誤發(fā)生,則會在重復(fù)的索引記錄上設(shè)置一把共享鎖陋率,在多個session同時插入一行球化,且另外的某個session已經(jīng)持有了該索引記錄的排他鎖時,共享鎖的使用可能導(dǎo)致死鎖的出現(xiàn)瓦糟。
事務(wù)隔離級別為RC模式
事務(wù)隔離級別為RC模式時筒愚,默認(rèn)Gap鎖被禁用,next key lock也被禁用菩浙,只剩下行鎖了巢掺。