事務隔離級別 事務併發可能出現的問題 臟寫 事務之間對增刪改互相影響 臟讀 事務之間讀取其他未提交事務的數據 不可重覆讀 一個事務在多次執行一個select讀到的數據前後不相同。因為被別的未提交事務修改,刪除數據或數據被更新被當前事務讀取到了。 幻讀 一個事務在第一次讀取正常數據,第二次讀取到其他未 ...
事務隔離級別
事務併發可能出現的問題
- 臟寫 事務之間對增刪改互相影響
- 臟讀 事務之間讀取其他未提交事務的數據
- 不可重覆讀 一個事務在多次執行一個select讀到的數據前後不相同。因為被別的未提交事務修改,刪除數據或數據被更新被當前事務讀取到了。
- 幻讀 一個事務在第一次讀取正常數據,第二次讀取到其他未提交事務的insert記錄,導致讀取一個不存在的記錄。指一次讀取讀取到了之前未讀取到的數據。
事務的4個隔離級別,以及解決的問題
- READ UNCOMMITTED 未提交讀 解決臟寫
- READ COMMITTED提交讀 解決臟寫、臟讀
- REPEATABLE READ可重覆讀 解決臟寫、臟讀、不可重覆讀
- SERIALIAZBLE可串列化 解決臟寫、臟讀、不可重覆讀、幻讀
四個隔離級別和可以解決的問題是SQL專門規定的,但是在Innodb引擎下,在可重覆讀的隔離級別的下就可以直接解決幻讀的問題。
我們可以在啟動時指定系統參數修改系統預設的隔離級別,預設為可重覆讀。
mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set, 1 warning (0.00 sec)
MVCC
版本鏈
我們在前面就講過了undo日誌,對於每次進行增刪改就會產生undo日誌,這時每個數據行的roll_pointer就會指向一個undo鏈表,我們就稱其為版本鏈。我們在提一嘴,因為insert的undo日誌在提交後是沒有用的,所以在事務提交後insert的undo就會被釋放。
可以到前面的文章瞭解一下undo日誌。大概知道undo日誌的類型和產生的過程就OK了感覺怎麼存儲undo日誌的那一部分講得雲里霧裡https://www.cnblogs.com/duizhangz/p/16333565.html
為什麼沒用?因為插入並不維護舊值,只是表明一個插入,並不需要存儲什麼信息。所以在事務提交時直接釋放掉。因為事務在回滾時需要由一條insert語句類型的undo進行回滾。
這就是上面倆事務生成的版本鏈。
undo鏈表頭存儲的就是最新事務更新的記錄信息。
ReadView
對於不同的事務隔離級別,我們可以讀取的記錄數據是不一樣的。
-
對於未提交讀的隔離級別來說,我們可以直接讀到數據的最新版本。
-
對於提交讀的隔離級別來說,我們需要可以讀到的就是已經提交的事務的修改數據。
-
對於可重覆讀的隔離級別來說,我們需要可以讀到在事務開啟前已經提交的事務的數據。
-
對於串列讀的隔離節別來說,Innodb採用加鎖的方式來保證串列讀。
對於中間兩個隔離級別,就需要ReadView這個結構來實現MVCC。以下是ReadView的結構
- m_ids : 表示在生成ReadView時當前系統中活躍的讀寫事務ID的列表
- min_trx_id : 表示在生成ReadView時當前系統中活躍的讀寫事務ID的最小值即在m_ids中最小的事務ID。
- max_trx_id : 表示生成ReadView時系統中應該分配給下一個事務的ID。
- creator_trx_id : 表示生成該ReadView的事務ID。
有了ReadView這個結構,我們在就可以對事務進行控制。
- 當被訪問的記錄行的事務ID大於等於max_trx_id,說明當前數據行不可見。
- 當被訪問的記錄行的事務ID小於min_trx_id,可以直接獲得數據。
- 當被訪問的記錄行的事務ID等於creator_trx_id,說明是當前事務修改的記錄,可以直接訪問。
- 當被訪問的記錄行的事務ID大於min_trx_id且小於max_trx_id,我們需要判斷一下這個事務ID是不是在m_ids列表中,因為由可能是一個很早的事務很久還執行不介紹,導致中間的事務都結束了,如果在m_ids列表中,說明是活躍的,當前記錄行不能訪問,否則可以訪問數據行。
當前情況在版本鏈中從頭到尾遍歷,直到獲得到數據。
上面提到的提交讀和可重覆讀,因為是兩個隔離級別有區別的,兩個隔離級別的實現只要在ReadView的時機上進行把控,就可以實現。
- 提交讀,我們只要保證當前事務的每個語句能讀到已經提交的事務的數據。就可以在每個查詢數據進行前,事務就會創建一個ReadView。
- 可重覆讀,我們只要保證當前事務每個語句能讀到事務開啟前的數據,就可以在事務第一次讀取數據時會創建ReadView,然後整個事務只會使用這個ReadView去判斷能讀取的數據行。
仔細品一品,一下就可以恍然大悟。
這個MVCC只會在我們使用普通select查詢才會生效。