mysql可重複讀現象及原理分析html
MySQL事務隔離級別和MVCC (undo日誌版本鏈,ReadView) MVCC文章勘誤sql
可重複讀的實現併發
Repeatable Read(可重複讀):一個事務在執行過程當中能夠看到其餘事務已經提交的新插入的記錄(讀已經提交的,實際上是讀早於本事務開始且已經提交的),可是不能看到其餘事務對已有記錄的更新(即晚於本事務開始的),而且,該事務不要求與其餘事務是「可串行化」的。(沒有問題)mvc
這句話的核心,是「可是不能看到其餘事務對已有記錄的更新」,那麼RR隔離級別是怎麼保證這一點的呢?post
事務ID是遞增的。spa
使用MVCC(多版本併發控制)。InnoDB爲每行記錄添加了一個事務ID,每當修改數據時,將當事務ID寫入。
在讀取事務開始時,系統會給事務一個當前版本號(事務ID),事務會讀取版本號<=當前版本號的數據,這時就算另外一個事務插入一個數據,並立馬提交,新插入這條數據的版本號會比讀取事務的版本號高,所以讀取事務讀的數據仍是不會變。.net
可是,當前事務想再寫這行數據的話,仍是以數據庫提交的數據爲準。而且會加行鎖,其餘的事務要再來修改的話,就得等到當前事務結束。命令行
舉例:
咱們先看看現象,再分析原理。個人mysql版本是5.5。
下面是一張表,只有一條數據,而且我開啓了事物
此時,另外一個事物將record加1,所以我在開啓一個命令行客戶端,執行下面的命令:
成功加1以後,實際上,數據庫中record確定是2。
而後回到以前的客戶端,再查一次:
沒毛病,record仍是1,果真是可重複讀。有些人覺得mysql的可重複讀是經過行鎖實現的,
從上面能夠知道,確定不是,若是是的話,第一次select * from test的時候,id=1的記錄就會加行鎖,我都加行鎖了,我還沒提交,另外的事物是怎麼update成功的。
結論就是mysql使用的MVCC(多版本併發控制),MVCC詳解能夠看:https://blog.csdn.net/whoamiyang/article/details/51901888
咱們繼續,我以前的第一個事物還沒提交,不過提交以前,我也想加1;
加完以後我再查一下,額,record是3,好像很奇怪,但也不奇怪。
其實,update test set record=record+1 where id=1;這條語句中,在加1以前,他知道本身等於2,而後2+1=3。
也就是說,update時讀取數據是最新版本的數據,而select是到當前事物版本爲止的數據。當更新成功以後,當前版本即爲最新版本,再次select,讀取的是最新的數據。
在這裏討論下樂觀鎖的必要性。下面是樂觀鎖的實現,實現樂觀鎖,咱們通常會這麼作
update test set record=record+1 where id=1 and record=1;
若是不用樂觀鎖,你用select讀取到的值其實根本不許確。除非你開啓悲觀鎖,像下面這樣:
select * from test where id=1 for update;
這樣能夠讀取到最新的內容,同時在你當前的事物提交以前,其餘事物的update此條記錄將會鎖等待。
故事到此,尚未結束,此時咱們開啓事物三,也作加1操做看會發生什麼。
結果是,鎖等待超時,也就是說(事物一)在更新完後,會加行鎖,這個應該比較好理解。事物中,剛開始查詢的時候是不會加行鎖的,可是當有更新操做以後,會加行鎖,直到事物提交。
事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的所有數據行。 同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那麼,之後就會發生操做第一個事務的用戶發現表中還有沒有修改的數據行,就好象 發生了幻覺同樣。
1.在快照讀讀狀況下,mysql經過mvcc來避免幻讀。
2.在當前讀讀狀況下,mysql經過next-key來避免幻。
mvcc全稱是multi version concurrent control(多版本併發控制)。mysql把每一個操做都定義成一個事務,每開啓一個事務,系統的事務版本號自動遞增。每行記錄都有兩個隱藏列:建立版本號和刪除版本號
select:事務每次只能讀到建立版本號小於等於這次系統版本號的記錄,同時行的刪除版本號不存在或者大於當前事務的版本號。
update:插入一條新記錄,並把當前系統版本號做爲行記錄的版本號,同時保存當前系統版本號到原有的行做爲刪除版本號。
delete:把當前系統版本號做爲行記錄的刪除版本號
insert:把當前系統版本號做爲行記錄的版本號
行鎖+GAP間隙鎖
快照讀:簡單的select操做,屬於快照讀,不加鎖。(固然,也有例外,下面會分析)
select * from table where ?;
當前讀:特殊的讀操做,插入/更新/刪除操做,屬於當前讀,須要加鎖。
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 ?;