首先要了解MVCC,MVCC叫做多版本并發控制,實際上就是保存了資料在某個時間節點的快照,
我們每行數實際上隱藏了兩列,創建版本號,過期(洗掉)版本號,每開始一個新的事務,版本號都會自動遞增,
拿user表舉例子,假設我們插入兩條資料,他們實際上應該長這樣 , 創建版本號是遞增的,
| id | name | create_version | delete_version |
|---|---|---|---|
| 1 | 張三 | 1 | |
| 2 | 李四 | 2 |
這時候假設小明去執行查詢,此時也是會默認開啟一個事務 當前版本就是 current_version=3
select * from user where id<=3;
同時,小紅在這時候開啟事務去修改id=1的記錄,小紅事務版本是 current_version=4
update user set name='張三三' where id=1;
小紅執行成功后的結果是這樣的
| id | name | create_version | delete_version |
|---|---|---|---|
| 1 | 張三 | 1 | |
| 2 | 李四 | 2 | |
| 1 | 張三三 | 4 |
同時 , 還有小黑在洗掉id=2的資料,小黑的版本是 current_version=5,小黑執行后結果是這樣的,
| id | name | create_version | delete_version |
|---|---|---|---|
| 1 | 張三 | 1 | |
| 2 | 李四 | 2 | 5 |
| 1 | 張三三 | 4 |
由于MVCC的原理是查找創建版本小于或等于當前事務版本,洗掉版本為慷訓者大于當前事務版本,小明的真實的查詢應該是這樣
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 |
小明執行插入名字'王五'的記錄,發現唯一索引沖突,無法插入,查詢的時候分明看不到王五 , 但是插入總是說重復了 , 這就是幻讀,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/262878.html
標籤:其他
