首先要了解MVCC,MVCC叫做多版本并發(fā)控制,實(shí)際上就是保存了數(shù)據(jù)在某個(gè)時(shí)間節(jié)點(diǎn)的快照。 我們每行數(shù)實(shí)際上隱藏了兩列,創(chuàng)建版本號(hào),過(guò)期(刪除)版本號(hào),每開(kāi)始一個(gè)新的事務(wù),版本號(hào)都會(huì)自動(dòng)遞增。
拿user表舉例子,假設(shè)我們插入兩條數(shù)據(jù),他們實(shí)際上應(yīng)該長(zhǎng)這樣 , 創(chuàng)建版本號(hào)是遞增的。
這時(shí)候假設(shè)小明去執(zhí)行查詢,此時(shí)也是會(huì)默認(rèn)開(kāi)啟一個(gè)事務(wù) 當(dāng)前版本就是 current_version=3 select * from user where id<=3;
同時(shí),小紅在這時(shí)候開(kāi)啟事務(wù)去修改id=1的記錄,小紅事務(wù)版本是 current_version=4 update user set name='張三三' where id=1; 小紅執(zhí)行成功后的結(jié)果是這樣的
同時(shí) , 還有小黑在刪除id=2的數(shù)據(jù),小黑的版本是 current_version=5,小黑執(zhí)行后結(jié)果是這樣的。
由于MVCC的原理是查找創(chuàng)建版本小于或等于當(dāng)前事務(wù)版本,刪除版本為空或者大于當(dāng)前事務(wù)版本,小明的真實(shí)的查詢應(yīng)該是這樣 select * from user where id<=3 and create_version<=3 and (delete_version>3 or delete_version is null); 所以小明最后查詢到的id=1的名字還是'張三',并且id=2的記錄也能查詢到。這樣做是為了保證事務(wù)讀取的數(shù)據(jù)是在事務(wù)開(kāi)始前就已經(jīng)存在的,要么是事務(wù)自己插入或者修改的。
幻讀是這樣的 , 比如下面的增加用戶的例子 ,假定用戶名是唯一索引不允許重復(fù) 小明想要插入一條王五的數(shù)據(jù) , 開(kāi)啟事務(wù)current_version=6查詢名字為 '王五'的記錄,發(fā)現(xiàn)不存在。 同時(shí)小紅開(kāi)啟事務(wù)current_version=7插入一條 王五的數(shù)據(jù),結(jié)果是這樣:
小明執(zhí)行插入名字'王五'的記錄,發(fā)現(xiàn)唯一索引沖突,無(wú)法插入,查詢的時(shí)候分明看不到王五 , 但是插入總是說(shuō)重復(fù)了 , 這就是幻讀。 |
|