數據庫和MVCC多版本併發控制基本介紹能夠參考以前的文章 數據庫和MVCC多版本併發控制。算法
本文全部內容基於MySQL/InnoDB引擎。sql
髒讀、不可重複讀和幻讀都是數據庫讀一致性問題,須要由數據庫提供必定的事務隔離機制來解決。數據庫
(1)鎖機制segmentfault
解決寫-寫衝突問題。在讀取數據前,對其加鎖,防止其它事務對該數據進行修改。併發
悲觀鎖post
每每依靠數據庫提供的鎖機制。cdn
樂觀鎖對象
大可能是基於數據版本記錄機制來實現。blog
(2)MVCC多版本併發控制事務
解決讀-寫衝突問題。不用加鎖,經過必定機制生成一個數據請求時間點時的一致性數據快照, 並用這個快照來提供必定級別 (語句級或事務級) 的一致性讀取。這樣在讀操做的時候不須要阻塞寫操做,寫操做時不須要阻塞讀操做。
兩段鎖
加鎖/解鎖是兩個不相交的階段,加鎖階段:只加鎖,不解鎖。解鎖階段:只解鎖,不加鎖。
按照鎖粒度維度來看,MySQL數據庫根據不一樣的存儲引擎能夠有表級鎖、頁級鎖和行級鎖。
MySQL中鎖定粒度最大的一種鎖,對當前操做的整張表加鎖,實現簡單,資源消耗也比較少,加鎖快,不會出現死鎖。其鎖定粒度最大,觸發鎖衝突的機率越高,併發度最低,MyISAM和InnoDB引擎都支持表級鎖。
Mysql中鎖定粒度最小的一種鎖,只針對當前操做的行進行加鎖。行級鎖能大大減小數據庫操做的衝突。其加鎖粒度最小,併發度高,但加鎖的開銷也最大,加鎖慢,會出現死鎖。
雖然使用行級鎖具備粒度小、併發高等特色,可是表級鎖在某些場景下也是必需的。
按照是否兼容來分類,表級鎖和行級鎖能夠再細分爲共享鎖和排它鎖。
共享鎖(Share Locks,簡記爲S鎖)又稱爲讀鎖。其它事務能夠併發地讀取數據,能夠再加共享鎖,但任何事務都不能獲取數據上的排它鎖,直至已經釋放全部共享鎖。
排它鎖(Exclusive lock,簡記爲X鎖)又稱爲寫鎖。若事務對數據對象加上了排它鎖,則只容許該事務對數據對象進行讀取和修改,其它事務不能再對數據對象加任何類型的鎖,直到該事務釋放對象上的排它鎖。在更新操做(INSERT、UPDATE 或 DELETE)過程當中始終應用排它鎖。
爲了容許行鎖和表鎖共存,實現多粒度鎖機制,InnoDB還有兩種內部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖。
意向共享鎖(IS)
表示事務準備給數據行加入共享鎖,事務在給一個數據行加共享鎖以前必須先取得該表的IS鎖。
意向排它鎖(IX)
表示事務準備給數據行加入排它鎖,事務在給一個數據行加排它鎖以前必須先取得該表的IX鎖。
MySQL中表鎖和行鎖共存,若不引入意向鎖,該如何判斷是否鎖衝突呢?
假設事務T要對錶T1加X鎖,那就必需要判斷T1表下每個數據行是否加了S鎖或者X鎖。這樣作的效率會很是低,須要對整個表進行遍歷。在引入意向鎖以後狀況變得簡單了。
假設事務T要對錶T1加X鎖,在這以前假設已經有事務A對數據行R加了S鎖,那麼此時表上已經有IS鎖了(事務在給一個數據行加S鎖以前必須先取得該表的IS鎖)。因爲X鎖和IS鎖衝突,因此事務T須要等待鎖操做完成。這樣就省去了遍歷的操做,提升了衝突判斷效率。
InnoDB的鎖兼容狀況以下所示。
InnoDB主要實現了三種行鎖算法。
Record Lock
記錄鎖,鎖定一個行記錄
Gap Lock
間隙鎖,鎖定一個區間
Next-Key Lock
記錄鎖+間隙鎖,鎖定行記錄和區間
Gap Lock和Next-Key Lock是爲了解決幻讀問題。
咱們知道MVCC裏面Repeated Read級別是快照讀,read view是在執行事務中第一條select語句的瞬間建立,後續全部的select都是複用這個對象,因此能保證每次讀取的一致性。但是這並不能確保就不會出現幻讀問題了,仍然可能在執行insert/update時遇到幻讀現象,由於SELECT 不加鎖的快照讀行爲是沒法限制其餘事務對新增重合範圍的數據的插入的。可能會出現這樣的狀況,select出了2條記錄,update的時候卻返回了3個成功結果。
InnoDB經過間隙鎖來鎖定區間間隔,避免其它事務在這個區間內插入其它數據致使出現幻讀現象。
在MySQL的規範裏面RR事務級別是可能出現幻讀的,InnoDB經過間隙鎖避免了這種狀況。這個實現和規範有所差異。另外,Next-Key Lock是Repeated Read級別纔會有的,在Read Committed級別並不存在。
示例
假設表T1(id private key),一共有3條記錄一、三、5,同時有兩個事務在進行。
事務A在T2時刻查詢的結果爲5,因爲使用select … for update語句,這會在區間(3,+∞)這個範圍內加上Gap Lock, 所以在這個區間內的插入都是不被容許的。因此T6時刻查詢結果也是5,避免了幻讀現象。事務B在T4時刻想插入4,這個屬於(3,+∞)區間,所以寫入會被阻塞,直到事務A結束。