對於事務的隔離級別及innodb的對各類隔離級別的實現方式一直以來都不是徹底理解,故整理了本片文章但願能和你們一塊兒學習,探討~~算法
隔離級別 | 髒讀(Dirty Read) | 不可重複讀(NonRepeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
未提交讀(Read uncommitted) | v | v | v |
已提交讀(Read committed) | x | v | v |
可重複讀(Repeatable read) | x | x | v |
可串行化(Serializable ) | x | x | x |
不通的隔離級別形成不一樣的影響,主要緣由是由一個事務的的讀取在另一個事務不一樣的生命週期致使的,例如:sql
時間點 | 事務A | 事務B |
---|---|---|
1 | 開啓事務A | |
2 | 開啓事務B | |
3 | 查詢庫存爲100 | |
4 | 庫存增長至150 | |
5 | 查詢庫存爲150 |
時間點 | 事務A | 事務B |
---|---|---|
1 | 開啓事務A | |
2 | 開啓事務B | |
3 | 查詢庫存爲100 | |
4 | 庫存增長至150 | |
5 | 查詢庫存爲100 | |
6 | 提交事務 | |
7 | 查詢庫存爲150 |
時間點 | 事務A | 事務B |
---|---|---|
1 | 開啓事務A | |
2 | 開啓事務B | |
3 | 查詢庫存爲100 | |
4 | 庫存增長至150(阻塞) | |
5 | 查詢庫存爲100 | |
6 | 繼續阻塞 | |
7 | 提交事務 | |
8 | 更新庫存 |
注意:這裏只是innodb的rr模式下當前讀的處理機制
能夠看出rr模式下,不管事務是否提交,讀的結果都是相同的,這就能夠實現可重複讀。可是rr模式下,會出現幻讀(Phantom Read)現象:數據庫
時間點 | 事務A | 事務B |
---|---|---|
1 | 開啓事務A | |
2 | 開啓事務B | |
3 | 查詢id<3的全部記錄,共3條 | |
4 | 插入一條記錄id=2 | |
5 | 提交事務 | |
6 | 查詢id<3的全部記錄,共4條 |
rr模式下,除了會出現幻讀以外,實際業務使用中還會出現丟失更新的問題:segmentfault
時間點 | 事務A | 事務B |
---|---|---|
1 | 開啓事務A | |
2 | 開啓事務B | |
3 | 查詢庫存s爲100 | |
4 | 更新庫存爲s爲150 | |
5 | 增長20庫存,即更新庫存位100+20=120 | |
6 | 提交事務 |
結果是庫存更新丟了b事務的更新,解決這種問題一般兩種方法併發
1.使用樂觀鎖
2.update table set s = s + 20;
到此基本上就是理論上各隔離級別下可能出現的問題,下面討論innodb是如何避免以上各種問題的。mvc
一、當前讀:即加鎖讀,讀取記錄的最新版本,會加鎖保證其餘併發事務不能修改當前記錄,直至獲取鎖的事務釋放鎖;高併發
使用當前讀的操做主要包括:顯式加鎖的讀操做與插入/更新/刪除等寫操做,以下所示:性能
select * from table where ? lock in share mode; select * from table where ? for update; insert into table values (…); update table set ? where ?; delete from table where ?;
二、快照讀:即不加鎖讀,讀取記錄的快照版本而非最新版本,經過MVCC實現;學習
InnoDB默認的RR事務隔離級別下,不顯式加『lock in share mode』與『for update』的『select』操做都屬於快照讀,保證事務執行過程當中只有第一次讀以前提交的修改和本身的修改可見,其餘的均不可見;測試
第一部分中討論的各類狀況都是針對當前讀的,innodb的rr隔離級別在當前讀下是經過加兩段加鎖避免了不可重複讀和幻讀現象,下面說一下innodb的鎖。
鎖類型 | S | X |
---|---|---|
S | 兼容 | 不兼容 |
X | 不兼容 | 不兼容 |
innodb的鎖算法
具體鎖算法可參考子梁兄的 講解
這裏爲了講解鎖算法咱們建立測試表t:
CREATE TABLE `t` ( `id` bigint, PRIMARY KEY (`id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO t SELECT 1; INSERT INTO t SELECT 2; INSERT INTO t SELECT 5;
表裏共有三條數據,咱們執行以下操做:
時間點 | 事務A | 事務B | |
---|---|---|---|
1 | begin; | ||
2 | begin; | ||
3 | select * from t where a = 5 for update; | ||
4 | insert into t (id) values (4); | ||
5 | commit(成功) |
這就實現了基本鎖算法降級,從Next-Key降級到Record Lock算法,相似具體鎖算法中有不少相似的降級目的就是爲了在保證一致性的前提下提升併發量。而innodb就是經過給查詢範圍內的全部數據加X鎖來阻塞其餘事務的插入更新操做,從而避免了不可重複讀和幻讀。雖然這樣避免了不可重複讀和幻讀,可是大大的下降了數據庫的併發性能。
一致性非鎖定讀(consistent nonlocking read)極大的提升了數據庫的併發性,也就是咱們一般多的快照讀,在innodb中經過MVCC實現快照讀。
MVCC的最大好處:讀不加任何鎖,讀寫不衝突,對於讀操做多於寫操做的應用,極大的增長了系統的併發性能;
InnoDB默認的RR事務隔離級別下,不顯式加『lock in share mode』與『for update』的『select』操做都屬於快照讀,使用MVCC,保證事務執行過程當中只有第一次讀以前提交的修改和本身的修改可見,其餘的均不可見。
mvcc避免幻讀未完待續