讀提交和可重複讀
Read Commit
讀提交,事務可以讀取已經提交的數據。
存在的問題:事務前後讀取不一致。
Repeatable Read
可重複讀,事務前後讀取數據是一致的。
存在的問題:無法處理插入或者刪除的數據。
MySql如何實現讀提交和可重複讀的?
innodb的聚簇索引中有2個隱藏字段,叫做trx_id (transaction id)
,和roll_pointer
。
trx_id
描述一個事務編號,roll_pointer
指向當前數據行的上一個歷史版本,對於insert
而言不存在歷史版本
同時存在一個ReadView對象,裏面有個隊列描述當前正在處理的事務id。當有事務讀取時,會先判斷讀取的行是否在這個隊列中,如果存在就不會讀取,會根據roll_pointer讀取上一個版本的數據。
例:當事務id爲100 的事務在修改id爲1的行時,ReadView中隊列會有[100]在裏面,這時另一個事務讀取id 爲1 的數據行會首先發現trx_id 100的 小明2號 數據,隨後會和ReadView的隊列元素比較,發現存在,則隨着roll_pointer去查詢trx_id爲60的數據行 小明1 ,發現60 不在隊列中,於是讀取值爲小明1。
Read Commit的問題復現:
以上圖爲例,當事務trx_id 爲 100 的事務修改 小明1 -> 小明2 時,此時未提交,於是另一個事務B在讀取時會讀取到 小明1,然後trx_id 爲100的事務提交,這時剛纔B又讀了一遍,發現值變成 小明2。
Repeatable Read 復現 Read Commit
當事務trx_id 爲 100 的事務修改 小明1 -> 小明2 時,此時未提交,於是另一個事務B在讀取時會讀取到 小明1,然後trx_id 爲100的事務提交,這時剛纔B又讀了一遍,值還是 小明1。
導致差異的原理
Read Commit在查詢時每次會生成新的ReadView,而Repeatable Read 則只會在第一次查詢時生成ReadView,隨後複用。
這導致Read Commit 每次查詢時那個隊列總是空的,就導致會讀取到剛更新的數據。