欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文解析MySQL的MVCC實現(xiàn)原理

 更新時間:2022年08月16日 09:24:21   作者:一燈架構(gòu)  
這篇文章主要介紹了MySQL的MVCC實現(xiàn)原理,MVCC全稱是Multi-Version?Concurrency?Control是一種并發(fā)控制的方法,通過維護(hù)一個數(shù)據(jù)的多個版本,減少讀寫操作的沖突

1. 什么是MVCC

MVCC全稱是Multi-Version Concurrency Control(多版本并發(fā)控制),是一種并發(fā)控制的方法,通過維護(hù)一個數(shù)據(jù)的多個版本,減少讀寫操作的沖突。

如果沒有MVCC,想要實現(xiàn)同一條數(shù)據(jù)的并發(fā)讀寫,還要保證數(shù)據(jù)的安全性,就需要操作數(shù)據(jù)的時候加讀鎖和寫鎖,這樣就降低了數(shù)據(jù)庫的并發(fā)性能。

有了MVCC,就相當(dāng)于把同一份數(shù)據(jù)生成了多個版本,在操作的開始各生成一個快照,讀寫操作互不影響。無需加鎖,也實現(xiàn)數(shù)據(jù)的安全性和事務(wù)的隔離性。

事務(wù)的四大特性中隔離性就是基于MVCC實現(xiàn)的。

說MVCC的實現(xiàn)原理之前,先說一下事務(wù)的隔離級別。

2. 事務(wù)的隔離級別

說隔離級別之前,先說一下并發(fā)事務(wù)產(chǎn)生的問題

臟讀: 一個事務(wù)讀到其他事務(wù)未提交的數(shù)據(jù)。

不可重復(fù)讀: 相同的查詢條件,多次查詢到的結(jié)果不一致,即讀到其他事務(wù)提交后的數(shù)據(jù)。

幻讀: 相同的查詢條件,多次查詢到的結(jié)果不一致,即讀到其他事務(wù)提交后的數(shù)據(jù)。

不可重復(fù)讀與幻讀的區(qū)別是: 不可重復(fù)讀是讀到了其他事務(wù)執(zhí)行update、delete后的數(shù)據(jù),而幻讀是讀到其他事務(wù)執(zhí)行insert后的數(shù)據(jù)。

再說一下事務(wù)的四大隔離級別:

Read UnCommitted(讀未提交): 讀到其他事務(wù)未提交的數(shù)據(jù),會出現(xiàn)臟讀、不可重復(fù)讀、幻讀。

Read Committed(讀已提交): 讀到其他事務(wù)已提交的數(shù)據(jù),解決了臟讀,會出現(xiàn)不可重復(fù)讀、幻讀。

Repeatable Read(可重復(fù)讀): 相同的條件,多次讀取到的結(jié)果一致。解決了臟讀、不可重復(fù)讀,會出現(xiàn)幻讀。

Serializable(串行化): 所有事務(wù)串行執(zhí)行,解決了臟讀、不可重復(fù)讀、幻讀。

隔離級別臟讀不可重復(fù)讀幻讀
讀未提交
讀已提交不會
可重復(fù)讀不會不會
串行化不會不會不會

MVCC只在Read CommittedRepeatable Read兩個隔離級別下起作用,因為Read UnCommitted隔離級別下,讀寫都不加鎖,Serializable隔離級別下,讀寫都加鎖,也就不需要MVCC了。

再談一下Undo log日志。

3. Undo Log(回滾日志)

Undo Log記錄的是邏輯日志,也就是SQL語句。

比如:當(dāng)我們執(zhí)行一條insert語句時,Undo Log就記錄一條相反的delete語句。

作用:

  • 回滾事務(wù)時,恢復(fù)到修改前的數(shù)據(jù)。
  • 實現(xiàn) MVCC 。

事務(wù)四大特性中原子性也是基于Undo Log實現(xiàn)的。

下面開始談一下MVCC的實現(xiàn)原理。

4. MVCC的實現(xiàn)原理

4.1 當(dāng)前讀和快照讀

先普及一下什么是當(dāng)前讀和快照讀。

當(dāng)前讀: 讀取數(shù)據(jù)的最新版本,并對數(shù)據(jù)進(jìn)行加鎖。

例如:insert、update、delete、select for update、 select lock in share mode。

快照讀: 讀取數(shù)據(jù)的歷史版本,不對數(shù)據(jù)加鎖。

例如:select

MVCC是基于Undo Log、隱藏字段、Read View(讀視圖)實現(xiàn)的。

4.2 隱藏字段

先說一下MySQL的隱藏字段,當(dāng)我們創(chuàng)建一張表時,InnoDB引擎會增加2個隱藏字段。

DB_TRX_ID(最近一次提交事務(wù)的ID):修改表數(shù)據(jù)時,都會提交事務(wù),每個事務(wù)都有一個唯一的ID,這個字段就記錄了最近一次提交事務(wù)的ID。

DB_ROLL_PTR(上個版本的地址):修改表數(shù)據(jù)時,舊版本的數(shù)據(jù)都會被記錄到Undo Log日志中,每個版本的數(shù)據(jù)都有一個版本地址,這個字段記錄的就是上個版本的地址。

4.3 版本鏈

當(dāng)我們第一次往用戶表插入一條記錄時,表數(shù)據(jù)和隱藏字段的值是下面這樣的:

insert into user (name,age) values ('一燈',1);

事務(wù)ID(DB_TRX_ID)是1,上個版本地址(DB_ROLL_PTR)是null。

image-20220814230054004.png

 第二次提交事務(wù),把用戶年齡加1。

update user set age=age+1 where id=1;

事務(wù)ID變成2,上個版本地址指向Undo Log中的記錄。

image-20220814230233034.png

第三次提交事務(wù),再把用戶年齡加1。

update user set age=age+1 where id=1;

事務(wù)ID變成3,上個版本地址指向Undo Log中事務(wù)ID為2的記錄。

image-20220814230426413.png

這樣表記錄和Undo Log歷史數(shù)據(jù)就組成了一個版本鏈。

4.4 Read View(讀視圖)

在事務(wù)中,執(zhí)行SQL查詢,就會生成一個讀視圖,是用來保證數(shù)據(jù)的可見性,即讀到Undo Log中哪個版本的數(shù)據(jù)。

快照讀一般是讀取的歷史版本的讀視圖,當(dāng)前圖會生成一個最新版本的讀視圖。

讀視圖是基于下面幾個字段實現(xiàn)的:

m_ids :當(dāng)前系統(tǒng)中活躍的事務(wù)ID集合,即未提交的事務(wù)。

min_trx_id :m_ids中最小的ID

max_trx_id :下一個要分配的事務(wù)ID

creator_trx_id: 當(dāng)前事務(wù)ID

讀視圖決定當(dāng)前事務(wù)能讀到哪個版本的數(shù)據(jù),從表記錄到Undo Log歷史數(shù)據(jù)的版本鏈,依次匹配,滿足哪個版本的匹配規(guī)則,就能讀到哪個版本的數(shù)據(jù),一旦匹配成功就不再往下匹配。

數(shù)據(jù)可見性規(guī)則:

  • DB_TRX_ID = creator_trx_id 如果這個版本數(shù)據(jù)的事務(wù)ID等于當(dāng)前事務(wù)ID,表示數(shù)據(jù)記錄的最后一次操作的事務(wù)就是當(dāng)前事務(wù),當(dāng)前讀視圖可以讀到這個版本的數(shù)據(jù)。
  • DB_TRX_ID < min_trx_id 如果這個版本數(shù)據(jù)的事務(wù)ID小于所有活躍事務(wù)ID,表示這個版本的數(shù)據(jù)不再被事務(wù)使用,即事務(wù)已提交,當(dāng)前讀視圖可以讀到這個版本的數(shù)據(jù)。
  • DB_TRX_ID >= max_trx_id 如果這個版本數(shù)據(jù)的事務(wù)ID大于等于下一個要分配的事務(wù)ID,表示有新事務(wù)更新了這個版本的數(shù)據(jù),這種情況下,當(dāng)前讀視圖不可以讀到這個版本的數(shù)據(jù)。
  • min_trx_id <= DB_TRX_ID < max_trx_id 如果這個版本數(shù)據(jù)的事務(wù)ID在當(dāng)前系統(tǒng)中活躍的事務(wù)ID集合(m_ids)里面,表示這個版本的數(shù)據(jù)被其他事務(wù)更新過,當(dāng)前讀視圖不可以讀到這個版本的數(shù)據(jù)。 如果這個版本數(shù)據(jù)的事務(wù)ID不在當(dāng)前系統(tǒng)中活躍的事務(wù)ID集合(m_ids)里面,表示是在其他事務(wù)提交后創(chuàng)建的讀視圖,當(dāng)前讀視圖可以讀到這個版本的數(shù)據(jù)。

5. 不同隔離級別下可見性分析

在不同的事務(wù)隔離級別下,生成讀視圖的規(guī)則不同:

  • READ COMMITTED(讀已提交) :在事務(wù)中每一次執(zhí)行快照讀時都生成一個讀視圖,每個讀視圖中四個字段的值都是不同的。
  • REPEATABLE READ(可重復(fù)讀):僅在事務(wù)中第一次執(zhí)行快照讀時生成讀視圖,后續(xù)復(fù)用這個讀視圖。

5.1 READ COMMITTED(讀已提交)

設(shè)置MySQL隔離級別為讀已提交:

SET session TRANSACTION ISOLATION LEVEL READ COMMITTED;

image-20220815155838874.png

執(zhí)行兩個事務(wù),驗證一下:

image-20220815160030220.png

事務(wù)1第一次查詢時,會生成一個讀視圖,讀視圖的各個屬性如下:

屬性
m_ids1,2
min_limit_id1
max_limit_id3
creator_trx_id1

可見的版本鏈數(shù)據(jù)是:

image-20220815160452959.png

符號規(guī)則 DB_TRX_ID = creator_trx_id = 1,可以看到當(dāng)前版本的數(shù)據(jù)。

事務(wù)1第二次查詢時,會生成一個新的讀視圖,讀視圖的各個屬性如下:

屬性
m_ids1
min_limit_id1
max_limit_id3
creator_trx_id1

可見的版本鏈數(shù)據(jù)是:

image-20220815174212106.png

符號規(guī)則 min_trx_id <= DB_TRX_ID < max_trx_id(1<=2<3),并且當(dāng)前數(shù)據(jù)版本的事務(wù)ID不在當(dāng)前系統(tǒng)中活躍的事務(wù)ID集合,可以看到當(dāng)前版本的數(shù)據(jù)。

image-20220815192630458.png

同一個事務(wù)內(nèi),相同的查詢條件,查詢到的數(shù)據(jù)不一致,查到了其他事務(wù)更新過的數(shù)據(jù),也就是出現(xiàn)了不可重復(fù)讀的情況。

再看一下,在可重復(fù)讀隔離級別下,是怎么解決這個問題的。

5.2 REPEATABLE READ(可重復(fù)讀)

設(shè)置MySQL隔離級別為可重復(fù)讀:

SET session TRANSACTION ISOLATION LEVEL REPEATABLE READ;

image-20220815192509582.png

執(zhí)行兩個事務(wù),驗證一下:

image-20220815160030220.png

事務(wù)1第一次查詢時,會生成一個讀視圖,讀視圖的各個屬性如下:

屬性
m_ids1,2
min_limit_id1
max_limit_id3
creator_trx_id1

可見的版本鏈數(shù)據(jù)是:

image-20220815160452959.png

符號規(guī)則 DB_TRX_ID = creator_trx_id = 1,可以看到當(dāng)前版本的數(shù)據(jù)。

事務(wù)1第二次查詢時,會復(fù)用原有的讀視圖,讀視圖的各個屬性如下:

屬性
m_ids1,2
min_limit_id1
max_limit_id3
creator_trx_id1

可見的版本鏈數(shù)據(jù)是:

image-20220815174212106.png

符號規(guī)則 min_trx_id <= DB_TRX_ID < max_trx_id(1<=2<3),并且當(dāng)前數(shù)據(jù)版本的事務(wù)ID在當(dāng)前系統(tǒng)中活躍的事務(wù)ID集合,所以是不可以看到當(dāng)前版本的數(shù)據(jù)。

image-20220815193850487.png

由此得知,可重復(fù)讀隔離級別下,相同的查詢條件,兩次查詢到的結(jié)果相同,也就是解決了可重復(fù)讀的問題,是通過復(fù)用原有的讀視圖的方式解決的。

到此這篇關(guān)于一問解析MySQL的MVCC實現(xiàn)原理的文章就介紹到這了,更多相關(guān)MySQL MVCC實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深度解析MySQL啟動時報“The server quit without updating PID file”錯誤的原因

    深度解析MySQL啟動時報“The server quit without up

    這篇文章主要介紹了MySQL啟動時報“The server quit without updating PID file”錯誤的原因,需要的朋友可以參考下
    2017-05-05
  • MySQL中的常用函數(shù)

    MySQL中的常用函數(shù)

    這篇文章主要介紹了MySQL中的常用函數(shù)的相關(guān)資料,需要的朋友可以參考下
    2016-08-08
  • Mysql建表與索引使用規(guī)范詳解

    Mysql建表與索引使用規(guī)范詳解

    本篇文章是對Mysql建表和索引使用規(guī)范進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • 深入淺出的學(xué)習(xí)Mysql

    深入淺出的學(xué)習(xí)Mysql

    最近看了一本小書,網(wǎng)易技術(shù)部的《深入淺出MySQL數(shù)據(jù)庫開發(fā)、優(yōu)化與管理維護(hù)》,算是回顧一下mysql基礎(chǔ)知識。下面這篇文章主要介紹了學(xué)習(xí)Mysql的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-02-02
  • mysql 卡死 大部分線程長時間處于sending data的狀態(tài)

    mysql 卡死 大部分線程長時間處于sending data的狀態(tài)

    首先說明一下,這是個無頭的案子,雖然問題貌似解決了,不過到現(xiàn)在我也沒有答案,只是把這個問題拿出來晾晾
    2008-11-11
  • MySQL底層數(shù)據(jù)結(jié)構(gòu)選用B+樹的原因

    MySQL底層數(shù)據(jù)結(jié)構(gòu)選用B+樹的原因

    大家好,本篇文章主要講的是MySQL底層數(shù)據(jù)結(jié)構(gòu)選用B+樹的原因,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 一文介紹mysql中TINYINT取值范圍

    一文介紹mysql中TINYINT取值范圍

    本文主要介紹了mysql中TINYINT取值范圍,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • MySQL主從復(fù)制問題總結(jié)及排查過程

    MySQL主從復(fù)制問題總結(jié)及排查過程

    這篇文章主要介紹了MySQL主從復(fù)制問題總結(jié)及排查過程,mysql主從是常用的高可用架構(gòu)之一,也是使用最廣泛的的系統(tǒng)架構(gòu)。在生產(chǎn)環(huán)境中mysql主從復(fù)制有時會出現(xiàn)復(fù)制錯誤問題。下文更多內(nèi)容需要的小伙伴可以參考一下
    2022-03-03
  • mysql批量插入BulkCopy的實現(xiàn)

    mysql批量插入BulkCopy的實現(xiàn)

    本文主要介紹了mysql批量插入BulkCopy的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 優(yōu)化Mysql數(shù)據(jù)庫的8個方法

    優(yōu)化Mysql數(shù)據(jù)庫的8個方法

    本文通過8個方法優(yōu)化Mysql數(shù)據(jù)庫:創(chuàng)建索引、復(fù)合索引、索引不會包含有NULL值的列、使用短索引、排序的索引問題、like語句操作、不要在列上進(jìn)行運算、不使用NOT IN和<>操作
    2013-11-11

最新評論