SQL標準定義了4類隔離級別:
1 Read Uncommitted(讀未提交)。缺點:臟讀(一個事務讀取到另一事務未提交的數據)
2 Read Committed(讀提交)。解決了臟讀問題, 缺點:不可重復讀(同一個事務里面讀取到其他事務commit的數據,主要是針對于update)。
3?Repeatable Read(可重復重讀)。解決了不可重復讀,缺點:幻讀(同一個事務里面讀取到其他事務commit的數據,主要是針對于insert)。
4 Serializable(可串行化)。解決了不可重復讀,缺點:每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。
PS : 需要區分:不可重復讀(update)和幻讀(insert|delete)。
幻讀指當用戶讀取某一范圍的數據行時,另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻影” 行。
Innodb默認隔離級別是可重復讀(RR) :
? 1) 使用MVCC(多版本并發控制)來解決不可重復讀問題,
? 2) ?使用間隙鎖(Gap鎖)來解決幻讀。
所以說Innodb存儲引擎在默認隔離的隔離級別下已經能完全保證事物的隔離性要求,即達到SQL標準的Serializable隔離級別。
PS : Innodb存儲引擎支持XA事務,通過XA事務可以來支持分布式事務的實現,需要將隔離級別設置為Serializable。在Serializable這個級別下,select語句也會加上共享鎖(不要看到select就說不會加鎖了)。
一致性的非鎖定讀
MySQL為了減少鎖處理(包括等待其它鎖)的時間,提升并發能力,引入了快照讀的概念(即一致性的非鎖定讀)。
1 Innodb通過多版本并發控制(MVCC)技術來讀取當前時間數據庫中行的數據。如果讀取的正在執行Update,Delete,這時讀取操作不會因此而會等待行上鎖的釋放,相反Innodb會去讀取行的一個快照數據。
2 之所以叫非鎖定讀,因為不需要等待訪問的行上X鎖的釋放。快照的數據是指該行之前版本的數據,通過Undo段(主要用于事務的回滾)來實現。
3 只有Read Committed和Repeatable Read 兩種事務隔離級別才能使用MVCC(Read Uncommited由于是讀到未提交的,所以不存在版本的問題,而Serializable 則會對所有讀取的行加鎖),但是它們對于快照數據的定義是不相同的。
RC:總是讀取被鎖定行的最新一份快照數據;
RR:總是讀取事務開始時的行數據版本。
因此在RC隔離級別下,會產生不可重復讀的問題。因為它總是讀取的最新的快照。
Innodb鎖算法
Innodb有三種行鎖算法:
1) Record Lock:單個行記錄鎖
2 )Gap Lock:間隙鎖,鎖定一個范圍,但不包括本身
3)Next-Key Lock:Gap Lock + Record Lock ,鎖定一個范圍,并且包括本身
默認情況下,InnoDB工作在可重復讀隔離級別下,并且會以Next-Key Lock的方式對數據行進行加鎖,這樣可以有效防止幻讀的發生。Next-Key Lock是行鎖和間隙鎖的組合,當InnoDB掃描索引記錄的時候,會首先對索引記錄加上行鎖(Record Lock),再對索引記錄兩邊的間隙加上間隙鎖(Gap Lock)。加上間隙鎖之后,其他事務就不能在這個間隙修改或者插入記錄。
鎖選擇
例子: update from t1 set v2=0 where v1=5
1)如果v1是唯一索引(包括主鍵索引),使用Record Lock
2)如果v1沒有建立索引,此時會進行全表掃描,掃表的時候,要阻止其他任何的更新操作,所以上升為表鎖
3)如果v1是二級索引,使用Next-Key Lock
?