最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mysql中的隔離性原理詳解

 更新時間:2023年08月09日 08:29:59   作者:meihaoshy  
這篇文章主要介紹了mysql隔離性的原理,多版本并發(fā)控制(MVCC)是一種用來解決?讀-寫沖突?的無鎖并發(fā)控制,為事務(wù)分配單向增長的事務(wù)ID,為每個修改保存一個版本,版本與事務(wù)ID關(guān)聯(lián),讀操作只讀該事務(wù)開始前的數(shù)據(jù)庫的快照,需要的朋友可以參考下

數(shù)據(jù)庫并發(fā)的三種場景

  • 讀-讀 :不存在任何問題,也不需要并發(fā)控制
  • 讀-寫 :有線程安全問題,可能會造成事務(wù)隔離性問題,可能遇到臟讀,幻讀,不可重復(fù)讀
  • 寫-寫 :有線程安全問題,可能會存在更新丟失問題

在這三種場景中 讀-讀幾乎沒有任何問題 所以我們不需要并發(fā)控制

寫-寫并發(fā)只需要加鎖控制即可

所以說我們今天重點討論下讀-寫并發(fā)

MVCC

基本介紹

多版本并發(fā)控制( MVCC )是一種用來解決 讀-寫沖突 的無鎖并發(fā)控制

為事務(wù)分配單向增長的事務(wù)ID,為每個修改保存一個版本,版本與事務(wù)ID關(guān)聯(lián),讀操作只讀該事務(wù)開始前的數(shù)據(jù)庫的快照。 所以 MVCC 可以為數(shù)據(jù)庫解決以下問題

  • 在并發(fā)讀寫數(shù)據(jù)庫時,可以做到在讀操作時不用阻塞寫操作,寫操作也不用阻塞讀操作,提高了數(shù)據(jù)庫并發(fā)讀寫的性能
  • 同時還可以解決臟讀,幻讀,不可重復(fù)讀等事務(wù)隔離問題,但不能解決更新丟失問題

在我們理解MVCC之前 我們需要知道三個前提知識

  • 3個記錄隱藏字段
  • undo 日志
  • Read View

我們下面就分別先介紹下這三個隱藏字段

三個前提知識介紹

三個隱藏字段

  • DB_TRX_ID :6 byte,最近修改( 修改/插入 )事務(wù)ID,記錄創(chuàng)建這條記錄/最后一次修改該記錄的事務(wù)ID
  • DB_ROLL_PTR : 7 byte,回滾指針,指向這條記錄的上一個版本(簡單理解成,指向歷史版本就行,這些數(shù)據(jù)一般在 undo log 中)
  • DB_ROW_ID : 6 byte,隱含的自增ID(隱藏主鍵),如果數(shù)據(jù)表沒有主鍵, InnoDB 會自動以DB_ROW_ID 產(chǎn)生一個聚簇索引
  • 實際還有一個刪除flag隱藏字段, 既記錄被更新或刪除并不代表真的刪除,而是刪除flag變了

假設(shè)我們現(xiàn)在創(chuàng)建并且插入了一條數(shù)據(jù) 代碼和顯示如下

mysql> create table if not exists student(
name varchar(11) not null,
age int not null
);
mysql> insert into student (name, age) values ('張三', 28);
Query OK, 1 row affected (0.05 sec)
mysql> select * from student;
+--------+-----+
| name | age |
+--------+-----+
| 張三 | 28 |
+--------+-----+
1 row in set (0.00 sec)

實際上在Linux隱藏字段的效果就是

在這里插入圖片描述

對于上圖做出一定解釋

  • 假設(shè)插入的事務(wù)ID是9 那么TRX_ID字段實際上就是9
  • 因為這是我們插入的第一個數(shù)據(jù) 所以說隱式主鍵就是1
  • 因為這是第一個數(shù)據(jù) 沒有更前面的數(shù)據(jù)了 所以說回滾指針指向的就是空
  • 其實還有其他的隱藏字段 比如說flag等 上面沒有標(biāo)識出

undo log日志

mySQL 將來是以服務(wù)進(jìn)程的方式,在內(nèi)存中運行。我們之前所講的所有機制:索引,事務(wù),隔離性,日志等,都是在內(nèi)存中完成的,即在 MySQL 內(nèi)部的相關(guān)緩沖區(qū)中,保存相關(guān)數(shù)據(jù),完成各種判斷操作。然后在合適的時候,將相關(guān)數(shù)據(jù)刷新到磁盤當(dāng)中的。

所以,我們這里理解undo log,簡單理解成,就是 MySQL 中的一段內(nèi)存緩沖區(qū),用來保存日志數(shù)據(jù)的就行。

read view 快照

關(guān)于快照讀的知識下面模擬MVCC場景的時候會講

Read View就是事務(wù)進(jìn)行 快照讀 操作的時候生產(chǎn)的 讀視圖 (Read View),在該事務(wù)執(zhí)行的快照讀的那一刻,會生成數(shù)據(jù)庫系統(tǒng)當(dāng)前的一個快照,記錄并維護系統(tǒng)當(dāng)前活躍事務(wù)的ID(當(dāng)每個事務(wù)開啟時,都會被分配一個ID, 這個ID是遞增的,所以最新的事務(wù),ID值越大)

Read View 在 MySQL 源碼中,就是一個類,本質(zhì)是用來進(jìn)行可見性判斷的。 即當(dāng)我們某個事務(wù)執(zhí)行快照讀的時候,對該記錄創(chuàng)建一個 Read View 讀視圖,把它比作條件,用來判斷當(dāng)前事務(wù)能夠看到哪個版本的數(shù)據(jù),既可能是當(dāng)前最新的數(shù)據(jù),也有可能是該行記錄的 undo log 里面的某個版本的數(shù)據(jù)。

下面是 ReadView 結(jié)構(gòu),但為了減少同學(xué)們負(fù)擔(dān),我們簡化一下

class ReadView {
	// 省略...
private:
	/** 高水位:大于等于這個ID的事務(wù)均不可見*/
	trx_id_t m_low_limit_id;
	/** 低水位:小于這個ID的事務(wù)均可見 */
	trx_id_t m_up_limit_id;
	/** 創(chuàng)建該 Read View 的事務(wù)ID*/
	trx_id_t m_creator_trx_id;
	/** 創(chuàng)建視圖時的活躍事務(wù)id列表*/
	ids_t m_ids;
	/** 配合purge,標(biāo)識該視圖不需要小于m_low_limit_no的UNDO LOG,
	* 如果其他視圖也不需要,則可以刪除小于m_low_limit_no的UNDO LOG*/
	trx_id_t m_low_limit_no;
	/** 標(biāo)記視圖是否被關(guān)閉*/
	bool m_closed;
	// 省略...
};
m_ids; //一張列表,用來維護Read View生成時刻,系統(tǒng)正活躍的事務(wù)ID
up_limit_id; //記錄m_ids列表中事務(wù)ID最小的ID
low_limit_id; //ReadView生成時刻系統(tǒng)尚未分配的下一個事務(wù)ID,也就是目前已出現(xiàn)過的事務(wù)ID的最大值+1
creator_trx_id //創(chuàng)建該ReadView的事務(wù)ID

我們在實際讀取數(shù)據(jù)版本鏈的時候,是能讀取到每一個版本對應(yīng)的事務(wù)ID的,即:當(dāng)前記錄的DB_TRX_ID 。

那么,我們現(xiàn)在手里面有的東西就有,當(dāng)前快照讀的 ReadView 和 版本鏈中的某一個記錄的DB_TRX_ID 。

那么 現(xiàn)在我們的問題就是 當(dāng)前快照讀,應(yīng)不應(yīng)該讀到當(dāng)前版本記錄。一張圖,解決所有問題!

在這里插入圖片描述

如果查到不應(yīng)該看到當(dāng)前版本,接下來就是遍歷下一個版本,直到符合條件,即可以看到。上面的readview 是當(dāng)你進(jìn)行select的時候,會自動形成。

看到這里有的同學(xué)可能會產(chǎn)生這樣一個疑問 如何遍歷下個版本呢?

我們之前說過 undo log其實就是一個緩沖區(qū) 并且里面有著回滾指針連接著的各種數(shù)據(jù) (實際上就是單鏈表連接的各種數(shù)據(jù))

再次總結(jié)下

  • 我們第一次開啟事務(wù)的時候會生成一個read view的結(jié)構(gòu)體
  • 該結(jié)構(gòu)體中會記錄活躍的最小事務(wù)id和比最大事務(wù)id還要大一的事務(wù)id
  • 當(dāng)我們第一次select讀的時候會形成一個快照
  • 如果說當(dāng)前版本的TRX_ID小于最小的id 那么我們就可以見到
  • 如果當(dāng)前版本的TRX_ID大于等于最大ID我們就不能見到
  • 如果說在最小和最大區(qū)間里面 并且該TRX_ID不是活躍ID(已提交) 則我們可以看到
  • 如果說在最小和最大區(qū)間里面 并且TRX_ID還是活躍ID(未提交) 則我們不能看到

轉(zhuǎn)化成現(xiàn)實中的例子

現(xiàn)在的我們能夠看到我們出生之前所有人寫的作品 但是我們不能看到還未出生的人寫的作品

如果說寫書的人跟我們同一個時代 我們就要判斷這本書有沒有發(fā)表 (是否提交) 如果提交了我們就能看見 如果沒有提交 我們就不能看見

模擬MVCC場景

MVCC場景中有增刪改查 下面我們分別進(jìn)行討論

我們插入的時候只需要形成一條新的undo log版本鏈 將回滾指針指向前面的數(shù)據(jù) 如果需要回滾直接通過回滾指針找到需要覆蓋的數(shù)據(jù)進(jìn)行覆蓋即可

我們前面說過了 mysql中還有一個隱藏的falg字段 因此 如果需要刪除的話 只需要將flag標(biāo)志位設(shè)置即可

這是最麻煩的一個環(huán)節(jié) 我們使用一個例子來說明MVCC中的改

現(xiàn)在一個表中有如下的記錄

在這里插入圖片描述

現(xiàn)在有一個事務(wù)ID為10的事務(wù) 要修改表中的name張三為李四

  • 因為要修改 所以我們肯定要先給記錄上鎖
  • 修改之前 我們要將改之前的數(shù)據(jù)拷貝一份要undo log當(dāng)中 假設(shè)地址為0x11223344
  • 之后我們修改原始數(shù)據(jù)中name為李四 并且將回滾指向0x11223344這個地址
  • 事務(wù)10commit提交 釋放鎖

過程圖如下

在這里插入圖片描述

如果還有事務(wù)要修改新的數(shù)據(jù)就參考上面的步驟即可

于是乎我們就形成了一條基于鏈表記錄的歷史版本鏈 undo log里面的一個個歷史版本就稱為快照

現(xiàn)在我們明白了

  • 所謂的回滾其實就是拿歷史版本鏈中的某條數(shù)據(jù)覆蓋當(dāng)前數(shù)據(jù)

首先我們要理解兩個概念 當(dāng)前讀和快照讀

  • 當(dāng)前讀:讀取最新的記錄,就是當(dāng)前讀。增刪改,都叫做當(dāng)前讀,select也有可能當(dāng)前讀,比如select lock in share mode(共享鎖), select for update
  • 快照讀:讀取歷史版本。快照讀不會被加鎖。

多個事務(wù)同時增刪改的時候是當(dāng)前讀 需要加鎖 在串行化的隔離級別下 select也是當(dāng)前讀 需要加鎖

如果select是快照讀 那么和增刪改的當(dāng)前讀不沖突 所以說并行效率高 事務(wù)的隔離級別決定了select是當(dāng)期讀還是快照讀 具體的判斷方法可以參考前面read view部分的知識

RR和RC的區(qū)別

RR級別測試

演示一 兩邊開啟事務(wù) 右邊先進(jìn)行快照讀 左邊插入數(shù)據(jù)之后commit 右邊再進(jìn)行快照讀和當(dāng)前讀

在這里插入圖片描述

在這里插入圖片描述

我們可以發(fā)現(xiàn)的是 當(dāng)右邊使用快照讀的時候不管左邊有沒有commit 讀取到的數(shù)據(jù)是一樣的

而使用當(dāng)前讀的時候 我們可以發(fā)現(xiàn)讀取的數(shù)據(jù)就是最新的數(shù)據(jù)了 光靠這個一個試驗我們看不出來什么 接下來我們看演示二

演示二: 左右兩邊同時開啟一個事務(wù) 左邊先插入數(shù)據(jù)之后提交 右邊在左邊提交之后進(jìn)行快照讀

在這里插入圖片描述

我們發(fā)現(xiàn) 這個時候右邊的快照讀 讀取了最新的數(shù)據(jù)

對比這兩次試驗加上之前的read view部分學(xué)習(xí)我們不難做出以下的推斷

在RR級別下 第一次select快照讀的時候會生成一個read view快照 之后的讀取就按照這個快照進(jìn)行

而實際上在RC級別中 每一次的select快照都都會生成一個最新的read view快照

所以說RR和RC最本質(zhì)的區(qū)別就是 RR只會生成依次read view快照 而RC快照讀幾次就會生成幾次快照

四種隔離級別的不同處理方式

讀–未提交

直接當(dāng)前讀 不加鎖

串行化

當(dāng)前讀 加鎖

讀 提交

在RC級別中 每次的select讀取都是快照讀 每次都會生成一個最新的read view快照

可重復(fù)讀

在RR級別中 每次select讀取都是快照讀 并且都會遵循第一次select讀取時生成的read view快照

總結(jié)

在這里插入圖片描述

到此這篇關(guān)于mysql隔離性的原理的文章就介紹到這了,更多相關(guān)mysql隔離性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mysql日期和時間的間隔計算實例分析

    mysql日期和時間的間隔計算實例分析

    這篇文章主要介紹了mysql日期和時間的間隔計算,結(jié)合實例形式分析了mysql日期和時間間隔計算的相關(guān)操作技巧與注意事項,需要的朋友可以參考下
    2019-12-12
  • MySQL?的ANALYZE與?OPTIMIZE命令(最佳實踐指南)

    MySQL?的ANALYZE與?OPTIMIZE命令(最佳實踐指南)

    MySQL的ANALYZE?TABLE更新統(tǒng)計信息優(yōu)化查詢性能,OPTIMIZE TABLE重組表結(jié)構(gòu)回收空間,二者鎖級別與執(zhí)行時間不同,建議定期維護、備份并監(jiān)控,結(jié)合工具跟蹤表健康狀況以保持?jǐn)?shù)據(jù)庫穩(wěn)定運行,本文給大家介紹MySQL的ANALYZE與OPTIMIZE命令,感興趣的朋友一起看看吧
    2025-07-07
  • mysql 5.7.23 安裝配置方法圖文教程

    mysql 5.7.23 安裝配置方法圖文教程

    這篇文章主要為大家詳細(xì)介紹了mysql 5.7.23安裝配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • MySQL?字符串截取函數(shù)及用法詳解

    MySQL?字符串截取函數(shù)及用法詳解

    在MySQL中,字符串截取是常見的操作,主要用于從字符串中提取特定部分,MySQL?提供了多種函數(shù)來實現(xiàn)這一功能,包括?LEFT()、RIGHT()、SUBSTRING()、MID()、SUBSTR()?和?SUBSTRING_INDEX()?等,本文將詳細(xì)介紹這些函數(shù)的用法,并通過示例進(jìn)行說明,需要的朋友可以參考下
    2025-05-05
  • mysql之觸發(fā)器使用

    mysql之觸發(fā)器使用

    這篇文章主要介紹了mysql之觸發(fā)器使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2017-09-09
  • B-Tree的性質(zhì)介紹

    B-Tree的性質(zhì)介紹

    今天小編就為大家分享一篇關(guān)于B-Tree的性質(zhì)介紹,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • mysql數(shù)據(jù)被誤刪的恢復(fù)方案以及預(yù)防措施

    mysql數(shù)據(jù)被誤刪的恢復(fù)方案以及預(yù)防措施

    這篇文章主要介紹了幾種常見的MySQL數(shù)據(jù)恢復(fù)方法,包括使用備份、二進(jìn)制日志、InnoDB表空間恢復(fù)以及第三方工具,每種方法都有其優(yōu)缺點,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-02-02
  • MySQL快速對比數(shù)據(jù)技巧

    MySQL快速對比數(shù)據(jù)技巧

    這篇文章主要介紹了MySQL快速對比數(shù)據(jù)的方法以及技巧分享,如果對此有興趣,一起跟著小編學(xué)習(xí)下吧。
    2018-02-02
  • linux mysql5.5升級至mysql5.7的步驟與踩到的坑

    linux mysql5.5升級至mysql5.7的步驟與踩到的坑

    這篇文章主要介紹了linux mysql5.5升級至mysql5.7的詳細(xì)步驟,后面腳本之家小編為大家整理了多個補充,大家可以參考一下
    2021-01-01
  • mysql表空間結(jié)構(gòu)和日志的用途詳解

    mysql表空間結(jié)構(gòu)和日志的用途詳解

    這篇文章主要介紹了mysql表空間結(jié)構(gòu)和日志的用途,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-06-06

最新評論

广昌县| 苗栗县| 三门峡市| 沁阳市| 龙井市| 盐亭县| 如东县| 嘉兴市| 阿勒泰市| 洪湖市| 武宁县| 钟祥市| 台东市| 新丰县| 平安县| 滨海县| 大姚县| 安徽省| 宁化县| 攀枝花市| 沾化县| 弥勒县| 册亨县| 白城市| 辉县市| 尚义县| 乌苏市| 怀安县| 和顺县| 鄂托克旗| 方正县| 奉贤区| 柘荣县| 綦江县| 滁州市| 阿拉善左旗| 共和县| 惠来县| 河北区| 湘阴县| 博湖县|