深度剖析 MySQL 事務隔離!

概述

今天主要分享下MySQL事務隔離級別的實現原理,因爲只有InnoDB支持事務,所以這裏的事務隔離級別是指InnoDB下的事務隔離級別。

隔離級別

1、讀未提交:一個事務可以讀取到另一個事務未提交的修改。這會帶來髒讀,幻讀,不可重複讀問題

2、讀已提交:一個事務只能讀取另一個事務已經提交的修改。其避免了髒讀,仍然存在不可以重複讀和幻讀問題

3、可重複讀:同一個事務中多次讀取相同的數據返回的結果是一樣的。其避免了髒讀和不可重複讀問題,但是幻讀依然存在

4、串行化:事務串行之行。避免了以上所有問題
在這裏插入圖片描述
以上是SQL-92標準中定義的四種隔離級別。在MySQL中,默認的隔離級別是REPEATABLE-READ(可重複讀),並且解決了幻讀問題。

注:不可重複讀重點在於Update和delete,而幻讀的重點在於insert。

MVCC

MVCC的全稱是多版本併發控制。MVCC使得InnoDB的事務隔離級別下執行一致性讀操作有了保證。

簡單說就是爲了查詢一些正在被另一個事務更新的行,並且可以看到它們被更新之前的值。這是一個用來增強併發性的強大技術,可以使得查詢不用等待另一個事務釋放鎖。

如下圖所示:
在這裏插入圖片描述
MVCC會給每一行增加三個字段,分別是:DB-TRX-ID、DB-ROLL-PTR、DB-ROW-ID

增刪查改

在InnoDB中,給每行增加兩個隱藏字段來實現MVCC,一個用來記錄數據行的創建時間,另一個用來記錄行的過期時間。

在實際操作中,存儲的並不是時間,而是事務版本號,每開啓一個新事務,事務的版本號就會遞增。所以增刪改查中對版本號的作用如下:

select:
讀取創建版本小於或等於當前事務版本號,並且刪除版本爲空或大於當前事務版本的記錄。這樣可以保證在讀取之前記錄都是存在的

insert:
將當前事務的版本號保存至行的創建版本號

update
新插入一行,並以當前事務版本號作爲新行的創建版本號,同時將原記錄行的刪除版本號設置爲當前事務版本號

delete
將當前事務版本號保存至行的刪除版本號

快照讀和當前讀

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

當前讀:讀取的是最新版版

普通的 select 就是快照讀,而 update,delete,insert,select…LOCK In SHARE MODE,SELECT…for update 就是當前讀

一致性非鎖定讀和鎖定讀

首先看看下面的圖:
在這裏插入圖片描述
1、鎖定讀

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

SELECT … LOCK IN SHARE MODE

SELECT … FOR UPDATE

SELECT … LOCK IN SHARE MODE:給記錄假設共享鎖,這樣其他事務職能讀不能修改,直到當前事務提交

SELECT … FOR UPDATE:給索引記錄加鎖,這種情況跟UPDATE的加鎖情況是一樣的

2、一致性非鎖定讀

consistent read(一致性讀),InnoDB用多版本來提供查詢數據庫在某個時間點的快照。

如果隔離級別是REPEATABLE READ,那麼在同一個事務中的所有一致性讀都讀的是事務中第一個的讀讀到的快照;如果是READ COMMITTED,那麼一個事務中的每一個一致性讀都會讀到它自己刷新的快照版本。

consistent read(一致性讀)是READ COMMITTED和REPEATABLE READ隔離級別下普通SELECT語句默認的模式。一致性讀不會給它鎖訪問的表加任何形式的鎖,因此其他事務可以同時併發的修改它們。

Record Locks(記錄鎖):在索引記錄上加鎖

Gap Locks(間隙鎖):在索引記錄之間加鎖,或者在第一個索引記錄之前加鎖,或者在最後一個索引記錄之後加鎖

Next-Key Locks:在索引記錄上加鎖,並且在索引記錄之前的間隙加鎖。相當於Record Locks與Gap Locks的一個結合

假如一個索引包含以下幾個值:10,11,13,20.那麼這個索引的next-key鎖將會覆蓋以下區間:

(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

總結

在默認的隔離級別中,普通的SELECT用的是一致性讀不加鎖。而對於鎖定讀,UPDATE和DELETE,則需要加鎖,至於加什麼鎖是有不同情況的。

如果對一個唯一索引使用了唯一的檢索條件,那麼只需要鎖定相應的索引記錄就好;如果是沒有使用唯一索引作爲檢索條件,或者用到了索引範圍掃描,那麼將會使用間隙鎖或者next-key鎖來以此阻塞其他會話向這個範圍內的間隙插入數據

利用MVCC實現一致性非鎖定讀,保證在同一個事務中多次讀取相同的數據返回的結果是一樣的,解決了不可重複讀問題.

利用Gap Locks和Next-key可以阻止其他事務在鎖定區間內插入數據,解決了幻讀問題.

總之,MySQL的默認隔離級別的實現依賴於MVCC和鎖,準確點說就是一致性讀和鎖。

因爲轉賬的交易場景 聯想到要加transaction事物 但是事物是什麼?
4個特性:原子性,一致性,隔離性,持久性
由於併發較大,session較多,事物存在幾個問題:
1、sessionA select sessionB update
但沒有commit session select 兩次查詢的數據不一樣
髒讀
2、sessionA select sessionB update成功了 sessionA select 兩次讀取的數據不一樣,導致不可重複讀
不可重複讀
3、sessionA select sessionB insert 成功了 sessionA select 讀了兩條數據
幻讀 數據庫爲了解決這三個問題,
sql92提出了事物的隔離級別 1、未提交讀:啥也不解決 2、已提交讀:不讀未提交的事物數據,解決了髒讀 3、可重複讀:解決不了幻讀 4、串行操作:缺點是效率太低,容易產生阻塞

上述隔離級別的實現方式是 1、snapshot 2、加上lock

lock又分行級鎖和表級鎖 以innoDb爲例:行級鎖,又分共享鎖和排他鎖 表級鎖:意向共享鎖和意向排它鎖,爲了解決效率問題

鎖的原理:是鎖的索引

鎖算法: 1、臨鍵鎖(next-key lock) innoDB:默認採用的是next-key
lock算法,因爲innoDB的設計默認是id爲自增主鍵 2、間隙鎖(gap lock)
屬於寫鎖:鎖的是間隙中的insert、update操作,不鎖select,這樣innoDB就解決了幻讀的問題 3、(記錄鎖)record

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章