InnoDB 鎖機制
數(shù)據(jù)讀寫可能存在的問題
如果事情能順順利利的按照我們預(yù)想的那樣進行下去,世界將會多么美好。
- 臟讀: 在一個事務(wù)A中讀取到另一個事務(wù)B未提交的數(shù)據(jù),事務(wù)B提交后A再讀數(shù)據(jù)又不一樣了
- 不可重復(fù)讀: 針對同一條數(shù)據(jù),兩次查詢的結(jié)果不一致(update & delete)
- 幻讀:兩次讀出來的數(shù)據(jù)數(shù)量不一致(insert)
臟讀和不可重復(fù)讀的區(qū)別在于:臟讀能讀到未提交的數(shù)據(jù),不可重復(fù)讀讀到了事務(wù)前后的數(shù)據(jù),兩者的表現(xiàn)都是針對同一條數(shù)據(jù),讀多次數(shù)據(jù)不一致。
不可重復(fù)讀和幻讀都是從數(shù)據(jù)一致性角度來看的,至于將數(shù)據(jù)修改操作和數(shù)據(jù)插入操作跟為兩種情況是因為解決這兩種情況的手段不一樣,下面會分析;
鎖種類
大類別上可以分為:
- 表鎖
- 行鎖:
從IO角度可以分為
- 讀鎖
- 寫鎖
表鎖會鎖住整個表的資源,性能很差,一般DDL操作會使用;大部分情況下對數(shù)據(jù)的操作都是行鎖,行鎖比較復(fù)雜,但是鎖住的數(shù)據(jù)少,對并發(fā)影響小,性能好,接下來主要討論行鎖。行鎖簡單點可以分為:
- 共享鎖(讀鎖):共享鎖不會影響其他的讀操作;
- 排他鎖(寫鎖):數(shù)據(jù)一旦有修改操作,鎖會升級為排他鎖,這時候其他事務(wù)不能讀,也不能修改這條數(shù)據(jù);需要注意的是,當(dāng)一個修改語句個where條件中沒有索引列時,這個鎖會變?yōu)楸礞i;
封鎖協(xié)議
一階段鎖協(xié)議
只開啟排他鎖不開啟共享鎖,排他鎖在事務(wù)結(jié)束后釋放
可以保證修改不丟失,會發(fā)生臟讀,因為沒有共享鎖,所以對于另外的事務(wù)而言,排他鎖不會影響到讀操作;
二階段鎖協(xié)議
在一階段基礎(chǔ)上開啟共享鎖,共享鎖在讀完數(shù)據(jù)后就釋放而不是事務(wù)結(jié)束后釋
保證修改不丟失的同時避免臟讀,因為有共享鎖,阻止自己讀取到其他事務(wù)中正在修改的數(shù)據(jù),從而避免臟讀;此時因為讀完數(shù)據(jù)就釋放,之后如果再有其他事務(wù)再一次對數(shù)據(jù)進行了修改并提交,在本事務(wù)中read就會出現(xiàn)不可重復(fù)讀現(xiàn)象;
三階段鎖協(xié)議
在二階段基礎(chǔ)上,共享鎖在事務(wù)結(jié)束后釋放而不是讀取完后就釋放
這個階段的手段是阻止后續(xù)的事務(wù)修改數(shù)據(jù),因為本事務(wù)在結(jié)束之前一直持有共享鎖,其他事務(wù)是獲取不到排他鎖的,從而實現(xiàn)可重復(fù)讀;
四階段鎖協(xié)議
這個最簡單,直接加表鎖,阻止其他事務(wù)所有操作,避免所有問題;
事務(wù)隔離級別
- ReadUncommited
- ReadCommited
- RepeatableRead:
- Serializable
這四種隔離級別看起來剛好跟上面的鎖協(xié)議對應(yīng),但是innodb 在此基礎(chǔ)上做了優(yōu)化(MVCC);