首先要了解MVCC,MVCC叫作多版本併發控制,實際上就是保存了數據在某個時間節點的快照。併發
咱們每行數實際上隱藏了兩列,建立版本號,過時(刪除)版本號,每開始一個新的事務,版本號都會自動遞增。編輯器
拿user表舉例子,假設咱們插入兩條數據,他們實際上應該長這樣 , 建立版本號是遞增的。spa
id | name | create_version | delete_version |
---|---|---|---|
1 | 張三 | 1 | |
2 | 李四 | 2 |
這時候假設小明去執行查詢,此時也是會默認開啓一個事務 當前版本就是 current_version=3索引
select * from user where id<=3;事務
同時,小紅在這時候開啓事務去修改id=1的記錄,小紅事務版本是 current_version=4io
update user set name='張三三' where id=1;table
小紅執行成功後的結果是這樣的原理
id | name | create_version | delete_version |
---|---|---|---|
1 | 張三 | 1 | |
2 | 李四 | 2 | |
1 | 張三三 | 4 |
同時 , 還有小黑在刪除id=2的數據,小黑的版本是 current_version=5,小黑執行後結果是這樣的。date
id | name | create_version | delete_version |
---|---|---|---|
1 | 張三 | 1 | |
2 | 李四 | 2 | 5 |
1 | 張三三 | 4 |
因爲MVCC的原理是查找建立版本小於或等於當前事務版本,刪除版本爲空或者大於當前事務版本,小明的真實的查詢應該是這樣select
select * from user where id<=3 and create_version<=3 and (delete_version>3 or delete_version is null);
因此小明最後查詢到的id=1的名字仍是'張三',而且id=2的記錄也能查詢到。這樣作是爲了保證事務讀取的數據是在事務開始前就已經存在的,要麼是事務本身插入或者修改的。
幻讀是這樣的 , 好比下面的增長用戶的例子 ,假定用戶名是惟一索引不容許重複
小明想要插入一條王五的數據 , 開啓事務current_version=6查詢名字爲 '王五'的記錄,發現不存在。
同時小紅開啓事務current_version=7插入一條 王五的數據,結果是這樣:
id | Name | create_version | delete_version |
---|---|---|---|
1 | 張三 | 1 | |
2 | 李四 | 2 | |
3 | 王五 | 7 |
小明執行插入名字'王五'的記錄,發現惟一索引衝突,沒法插入,查詢的時候分明看不到王五 , 可是插入老是說重複了 , 這就是幻讀。