天天看點

mysql mvvc 簡單了解

先說下我自己的了解,總結為圖如下:

mysql mvvc 簡單了解

MVCC的全稱是“多版本并發控制”。這項技術使得InnoDB的事務隔離級别下執行一緻性讀操作有了保證,換言之,就是為了查詢一些正在被另一個事務更新的行,并且可以看到它們被更新之前的值。這是一個可以用來增強并發性的強大的技術,因為這樣的一來的話查詢就不用等待另一個事務釋放鎖。這項技術在資料庫領域并不是普遍使用的。一些其它的資料庫産品,以及mysql其它的存儲引擎并不支援它。

mysql的innodb采用的是行鎖,而且采用了多版本并發控制來提高讀操作的性能。

什麼是多版本并發控制呢 ?其實就是在每一行記錄的後面增加兩個隐藏列,記錄建立版本号和删除版本号,

而每一個事務在啟動的時候,都有一個唯一的遞增的版本号。 

在InnoDB中,給每行增加兩個隐藏字段來實作MVCC,兩個列都用來存儲事務的版本号,每開啟一個新事務,事務的版本号就會遞增。

于是乎,預設的隔離級别(REPEATABLE READ)下,增删查改變成了這樣:

  • SELECT
    • 讀取建立版本小于或等于目前事務版本号,并且删除版本為空或大于目前事務版本号的記錄。這樣可以保證在讀取之前記錄是存在的。
  • INSERT
    • 将目前事務的版本号儲存至行的建立版本号
  • UPDATE
    • 新插入一行,并以目前事務的版本号作為新行的建立版本号,同時将原記錄行的删除版本号設定為目前事務版本号
  • DELETE
    • 将目前事務的版本号儲存至行的删除版本号

在插入操作時 : 記錄的建立版本号就是事務版本号。 

比如我插入一條記錄, 事務id 假設是1 ,那麼記錄如下:也就是說,建立版本号就是事務版本号。

id name create version delete version
1 xttblog 1

在更新操作的時候,采用的是先标記舊的那行記錄為已删除,并且删除版本号是事務版本号,然後插入一行新的記錄的方式。 

比如,針對上面那行記錄,事務Id為2 要把name字段更新。

1

update

table

set

name

=

'new_value'

where

id=1;

id name create version delete version
1 xttblog 1 2
1 xttblog.com 2

删除操作的時候,就把事務版本号作為删除版本号。比如:

1

delete

from

table

where

id=1;

id name create version delete version
1 xttblog.com 2 3

查詢操作:從上面的描述可以看到,在查詢時要符合以下兩個條件的記錄才能被事務查詢出來: 

  1. 删除版本号 大于 目前事務版本号,就是說删除操作是在目前事務啟動之後做的。 
  2. 建立版本号 小于或者等于 目前事務版本号 ,就是說記錄建立是在事務中(等于的情況)或者事務啟動之前。

這樣就保證了各個事務互不影響。從這裡也可以體會到一種提高系統性能的思路,就是:通過版本号來減少鎖的争用。另外,隻有read-committed和 repeatable-read 兩種事務隔離級别才能使用mVcc read-uncommited由于是讀到未送出的,是以不存在版本的問題。而serializable 則會對所有讀取的行加鎖。 

快照讀和目前讀

快照讀:讀取的是快照版本,也就是曆史版本

目前讀:讀取的是最新版本

普通的SELECT就是快照讀,而UPDATE、DELETE、INSERT、SELECT …  LOCK IN SHARE MODE、SELECT … FOR UPDATE是目前讀。

鎖定讀

在一個事務中,标準的SELECT語句是不會加鎖,但是有兩種情況例外。SELECT … LOCK IN SHARE MODE 和 SELECT … FOR UPDATE。

1

SELECT

... LOCK

IN

SHARE MODE

給記錄假設共享鎖,這樣一來的話,其它事務隻能讀不能修改,直到目前事務送出

1

SELECT

...

FOR

UPDATE

給索引記錄加鎖,這種情況下跟UPDATE的加鎖情況是一樣的

一緻性非鎖定讀

consistent read (一緻性讀),InnoDB用多版本來提供查詢資料庫在某個時間點的快照。如果隔離級别是REPEATABLE READ,那麼在同一個事務中的所有一緻性讀都讀的是事務中第一個這樣的讀讀到的快照;如果是READ COMMITTED,那麼一個事務中的每一個一緻性讀都會讀到它自己重新整理的快照版本。Consistent read(一緻性讀)是READ COMMITTED和REPEATABLE READ隔離級别下普通SELECT語句預設的模式。一緻性讀不會給它所通路的表加任何形式的鎖,是以其它事務可以同時并發的修改它們。

悲觀鎖和樂觀鎖

悲觀鎖,正如它的名字那樣,資料庫總是認為别人會去修改它所要操作的資料,是以在資料庫處理過程中将資料加鎖。其實作依靠資料庫底層。

樂觀鎖,如它的名字那樣,總是認為别人不會去修改,隻有在送出更新的時候去檢查資料的狀态。通常是給資料增加一個字段來辨別資料的版本。

MVCC實作一緻性非鎖定讀,這就有保證在同一個事務中多次讀取相同的資料傳回的結果是一樣的,解決了不可重複讀的問題。