前置知識
當前讀與快照讀
當前讀
什么是當前讀:讀取的是最新的資料,不會讀到老資料,
何時觸發:update、insert、delete、select lock in share mode、select for update時,總是當前讀,
快照讀
什么是快照讀:讀取的是歷史版本,不是最新的資料,
何時觸發:select

這些關系一定要搞清楚!
事務的ACID
原子性:事務要么全部成功,要么全部失敗,實作:undolog回滾日志實作,相當于存盤在磁盤中的歷史記錄鏈、還有一個更官方的名字:快照,
一致性:由另外三個共同達到一致性,
隔離性:事務并發執行時內部操作不能互相干擾,實作:鎖實作,
持久性:事務一旦提交,對資料庫的影回應該是永久的,實作:redolog實作,
Innodb引擎的日志
1、undolog
作用:保存歷史快照,
目的:實作原子性,在MVCC中也起到了一定的作用,
2、redolog
作用:預寫日志,
目的:為了高效實作持久性,將資料持久化,
詳解:首先,在執行資料更新時,效率是低的,目前幾乎所有軟體硬體的瓶頸,都卡在了IO層面,IO有兩種:順序讀寫、隨機讀寫,那明明是解釋redolog的,怎么就說起了IO呢?這要先明確一點,就是順序讀寫與隨機讀寫的效率是誰快誰慢的問題,順序讀寫:顧名思義,就是順序向尾部一次添加資料,屬于append的操作,不需要查找,隨機讀寫:需要指標的移動查找,所以很明顯,順序讀寫的效率是要遠高于隨機讀寫的,舉個例子,比如在一家飯店,中午有人來吃飯,這家店允許賒賬,所以很多人會選擇賒賬,而店主呢,就把所有的賒賬資訊記錄在一本厚厚的本子里,假設里面記了一萬條賒賬資訊,好了,中午最繁忙的時候,所有員工都在忙著作業,如果有人要賒賬,怎么辦?根本沒機會一個一個仔細找記錄,所以很自然的就會想到,我在墻上裝個黑板,或者單獨在一張紙上列出來今天的賒賬名單,等不忙了,我再慢慢地把名單記錄到本子里,所以,現在已經很明顯了,redolog就是順序讀寫,它快速記錄資料,然后資料再由順序讀寫區域慢慢向隨機讀寫區域轉換,這就是WAL:預寫日志,
redolog是Innodb引擎的日志,而MySQLserver中自帶的日志中有binlog,所以它倆是共存的,所以在運行時,必須保證一致性,因為binlog是MySQL主從復制時向從機同步資訊的,如果不寫binlog,那么從機會出問題,但是應該先寫哪一個呢?先寫哪個都會出問題!一旦寫第一個時斷電,就會造成主機與從機不一致,解決的方法是給redolog加個狀態,當redolog寫完資料后,給它狀態為prepare,然后去寫binlog,當binlog寫完后,再把redolog的狀態從prepare改為commit,這就是兩階段提交,
MVCC
宏觀來看,MVCC就是解決事務的隔離性的問題的,
MySQL的并發場景
MySQL的并發場景有三種:讀讀、讀寫、寫寫,
讀讀:不存在資料安全問題,
讀寫:存在資料安全問題,如臟讀、不可重復讀、幻讀,
寫寫:存在資料安全問題,如丟失更新,
而MVCC則是以不加鎖的方式解決讀寫沖突問題,
MVCC的組成部分
表的隱藏欄位:資料庫表在定義時除了自己宣告的欄位,還會包括一些隱藏欄位,包括有:
DB_TRX_ID :最近修改事務ID,指創建這條記錄或最后一次修改這條記錄的事務id,
DB_ROLL_PTR :回滾指標,指向記錄的上一個版本,即指向undolog首條記錄,
DB_ROW_ID :隱藏主鍵,如果表沒有主鍵,自動生成一個6位元組的row id,

readview
快照讀時會產生readview,即select時會產生readview,

舉個demo:

當select時,產生了快照讀,此時生成的readview可以看到,
而如何看能否讀取到值呢?MySQL有可見性演算法,

再舉一個demo

對比一下,如果按照我們的判斷,可以發現藍色的readview與第一個demo中的readview一模一樣,但是問題在于,藍色的select是不能讀取到修改之后的資料的,這當然是因為藍色的readview是錯誤的,它真正的readview其實就是黃色的readview,也就是下圖

結論
所以,隔離級別解決資料不可重復讀的關鍵,在于MVCC生成readview的機制或者時機,如果是讀已提交級別RC,每次快照讀都會生成readview,所以會產生不可重復讀的問題,如果是可重復讀隔離級別RR,只會在第一次快照讀時產生readview,不會有不可重復讀的問題,
至此,MVCC結束
至于幻讀問題,則需要加鎖來解決,幻讀產生的根本原因在于:當前讀和快照讀一起使用!如果一個事務中只有快照讀,那么永遠不會出現幻讀問題,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/500866.html
標籤:MySQL
