mysql mvcc多版本併發控制

2021-10-07 20:02:46 字數 2962 閱讀 5671

事務隔離的實現方案有兩種,lbcc和mvcc

基於鎖的併發控制,英文全稱lock-based concurrent control。這種方案比較簡單粗暴,就是乙個事務去讀取一條資料的時候,就上鎖,不允許其他事務來操作(當然這個鎖的實現也比較重要,如果我們只鎖定當前一條資料依然無法解決幻讀問題)。

這個概念其實很好理解,mysql加鎖之後就是當前讀。假如當前事務只是加共享鎖,那麼其他事務就不能有排他鎖,也就是不能修改資料;而假如當前事務需要加排他鎖,那麼其他事務就不能持有任何鎖。總而言之,能加鎖成功,就確保了除了當前事務之外,其他事務不會對當前資料產生影響,所以自然而然的,當前事務讀取到的資料就只能是最新的,而不會是快照資料(後文mvcc會解釋快照讀概念)。

在乙個事務中,標準的select語句是不會加鎖,但是有兩種情況例外。

(1)給記錄假設共享鎖,這樣一來的話,其它事務只能讀不能修改,直到當前事務提交

select ... lock in share mode

(2)給索引記錄加鎖,這種情況下跟update的加鎖情況是一樣的

select ... for update

mysql的大多數事務型儲存引擎實現的都不是簡單的行級鎖。基於提公升併發效能的考慮,他們一般都是同事實現了多版本併發控制(mvcc,mutil-version concurrency control)。不僅僅是mysql,包括oracle,postgresql等其他資料庫系統也都實現了mvcc,但是各自的實現機制不盡相同,因為mvcc沒有乙個統一的實現標準。

簡單理解,可以認為mvcc是行級鎖的乙個變種,但是它再很多情況下避免了加鎖操作,因此開銷更低,雖然實現機制有所不同,但大豆實現了非阻塞的讀操作,寫操作也只鎖定必要的行。

mvcc的實現,是通過儲存資料庫在某個時間點的快照來實現的,也就是說,不管需要執行多長時間,每個事務看到的資料都是一致的。根據事務開始的時間不同,每個事務對同一張表,同一時刻看到的資料是可能不一樣的。

之前說到了不同儲存引擎的mvcc實現是不同的,典型的有樂觀(optimistic)併發控制和悲觀(pessimistic)併發控制。

本文主要講mysql innodb 的mvcc實現,也是現在比較主流的儲存引擎

在innodb中,給每行增加兩個隱藏欄位來實現mvcc,乙個用來記錄資料行的建立時間,另乙個用來記錄行的過期時間(刪除時間)。在實際操作中,儲存的並不是時間,而是事務的版本號,每開啟乙個新事務,事務的版本號就會遞增。

但是嚴格來說,innodb會給資料庫中的每一行增加三個字段,它們分別是db_trx_id、db_roll_ptr、db_row_id(如果表設定了主鍵或者唯一索引,row_id則不會分配)。

db_roll_ptr

於是乎,預設的隔離級別(repeatable read)下,增刪查改變成了這樣:

insert

update

delete

儲存了這兩個額外系統版本號,使大多數讀操作都可以不用加鎖。這樣設計使得讀資料操作很簡單,效能很好,並且也能保證只會讀取到符合標準的行。不足之處是每行記錄都需要額外的儲存空間,需要做更多的行檢查工資,以及一些額外的維護工作。

注意:mvcc只在repeatable read 和 read committed 兩個隔離級別下工作。其他兩個級別和mvcc不相容

是不是很抽象,來個簡單的模擬例子:

1、清空原先的test表,事務a插入兩條資料,此時db_trx_id(事務id)為1,db_roll_ptr(回滾指標為null)

2、這時候事務b進行了一次查詢,會得到上面的結果,事務2還沒提交的時候又來了事務c,事務c插入了id=3的資料,此時表中的資料如下:

注意,這時候第3條資料的事務id為3,因為事務2也會產生乙個事務id

3、這時候事務b再次進行查詢,根據上面了解的,我們知道,這時候應該是查詢不出王五的,所以實際上二次查詢可能是這麼查的:

4、假如這時候事務d又來了,把id=1的資料給刪除了,這時候會把原資料的回滾指標記錄為當前的事務id:4,所以此時資料如下:

5、回到事務b,繼續查詢,應該還是只有1和2兩條資料,那麼他可能是這麼查詢的:

6、假如這時候又來了事務e,對第2條資料進行了更新,這時候會生產一條事務id為5的資料,並把原資料的回滾指標也同時標記為當前的事務id:5,那麼會得到如下資料:

根據上面猜測,執行下面的查詢:

這時候發現,查出來的資料還是只有1和2兩條。

有這樣三種鎖我們需要了解

在預設的隔離級別中,普通的select用的是一致性讀不加鎖。而對於鎖定讀、update和delete,則需要加鎖,至於加什麼鎖視情況而定。如果你對乙個唯一索引使用了唯一的檢索條件,那麼只需鎖定索引記錄即可;如果你沒有使用唯一索引作為檢索條件,或者用到了索引範圍掃瞄,那麼將會使用間隙鎖或者next-key鎖以此來阻塞其它會話向這個範圍內的間隙插入資料

普通的select才是快照讀,其它諸如update、刪除都是當前讀。修改的時候加鎖這是必然的,同時為了防止幻讀的出現還需要加間隙鎖。

綜上所述,預設隔離級別的實現依賴於mvcc和鎖,再具體一點是一致性讀和鎖。

《高效能mysql》

MYSQL MVCC多版本併發控制

innodb使用mvcc實現高併發 mvcc並不是mysql獨有的,oracle,postgresql等都實現了mvcc,但各自實現機制不同。因為mvcc沒有統一實現標準。mvcc可以認為它是行級鎖的乙個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。實現了非阻塞的讀操作,寫操作也只鎖定必要的...

mysql MVCC 多版本併發控制

mvcc是行級鎖的乙個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。大多數的mvcc都實現了非阻塞的讀操作,寫操作也只鎖定必要的行。主要是避免讀寫場景下加鎖控制的效能開銷。multiversion concurrency control 多版本併發控制 併發訪問 讀或者寫 資料庫時,對正在事...

Mysql MVCC多版本併發控制原理詳解

我們建立乙個hero表 create table hero number int,name varchar 100 country varchar 100 primary key number engine innodb charset utf8 然後向這個表裡插入一條資料 insert into ...