日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

什么是MVCC,一文搞懂MySQL的MVCC机制

發布時間:2024/1/1 数据库 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 什么是MVCC,一文搞懂MySQL的MVCC机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

MVCC是什么

MVCC,即Multi-Version Concurrency Control (多版本并發控制)。它是一種并發控制的方法,一般在數據庫管理系統中,實現對數據庫的并發訪問,在編程語言中實現事務內存。

數據庫中同時存在多個版本的數據,并不是整個數據庫的多個版本,而是某一條記錄的多個版本同時存在,在某個事務對其進行操作的時候,需要查看這一條記錄的隱藏列事務版本id,比對事務id并根據事物隔離級別去判斷讀取哪個版本的數據。

數據庫隔離級別讀已提交、可重復讀 都是基于MVCC實現的,相對于加鎖簡單粗暴的方式,它用更好的方式去處理讀寫沖突,能有效提高數據庫并發性能。

我們先回顧一下事務的相關概念,以便更好的理解mvcc的實現原理

MySQL的事務

redo log

redo log重做日志,是記錄物理數據變化的日志,使用數據庫DML對數據的修改操作,都會產生redo log,可以保證事務的持久性

undo log

undo log是回滾日志,有兩個作用:提供回滾操作多行版本控制(MVCC)

在數據修改的時候,不僅記錄了redo,還記錄了相對應的undo,如果因為某些原因導致事務失敗或回滾了,可以借助undo進行回滾,

undo log和redo log記錄物理日志不一樣,undo log主要記錄的是數據的邏輯變化,它是邏輯日志

可以認為執行insert時會對應在undo log中記錄一條delete語句,并且會記錄這個版本的事務id(txid),執行update語句會有一條update語句來使之數據恢復到上個版本。

當執行rollback時,就可以從undo log中的邏輯記錄讀取到相應的內容并進行回滾

多行版本控制的時候,也是通過undo log來實現的

當讀取的某一行被其它事務鎖定時,它可以從undo log中分析出該行記錄以前的數據是什么。從而提供該行版本信息。

并且undo log的內容變更也會記錄到redo log中,從而實現undo log的持久化

總而言之就是undo log提供了一種數據庫快照的功能,通過事務id和undo log我們可以找到歷史版本的數據

MySQL事務的隔離級別

SQL標準中定義了四個隔離級別:

  • READ-UNCOMMITTED(讀取未提交):最低的隔離級別,允許讀取尚未提交的數據變更,可能導致臟讀、幻讀、不可重復讀;
  • READ-COMMITTED(讀取已提交):允許讀取并發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀任有可能發生
  • REPAATABLE-READ(可重復讀):對同一字段的多次讀取結果都是一致的,除非數據本身是被本身事務所修改的,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生
  • SETIALIZABLE(可串行化):最高的隔離級別,完全服從ACID原則,所有事務單個依次執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀,不可重復讀以及幻讀。

MVCC原理

事務版本號

事務每次開啟前,都會從數據庫獲取一個自增長的事務ID,可以從事務ID判斷事務的執行先后順序

隱式字段

對于InnoDB存儲引擎,每一行記錄都有兩個隱藏列trx_idroll_ptr,如果表中沒有主鍵和非NULL唯一鍵時,則還會有第三個隱藏的主鍵列row_id

MySQL行記錄中除了記錄業務數據外,還有隱藏的 trx_idroll_ptr

  • trx_id:表示最近修改的事務的id,每次一個事務對某條聚集索引記錄進行改動時,都會把該事務的事務id賦值給trx_id隱藏列,新增一個事務時,trx_id就會遞增,因此trx_id能夠表示事務開始的先后順序
  • roll_ptr:指向上一個版本的地址,每次對某條聚集索引記錄進行改動時,都會把舊版本寫入undo log中,然后這個隱藏列就相當于一個指針,可以通過它來找到該記錄修改前的信息。

版本鏈

MySQL的每行記錄邏輯上其實是一個鏈表

演示說明:

update user set name = '肉蟹寶1' where id = 1

這個鏈表存在于undo log中,和最新版本的數據不在一起

每次更新后,都會將舊值放在一條undo log中,就算是該記錄的一個舊版本,隨著更新次數的增多,所有的版本都會被roll_ptr屬性連接成一個鏈表,我們把這個鏈表稱為版本鏈,版本鏈的頭節點就是當前記錄最新的值

另外,每個版本中還包含生成該版本時對應的事務id(trx_id)

ReadView

說完了undo log 和版本鏈,再來說說ReadView,前面我們說過MVCC只在read_commited和repeatable_read兩個隔離級別下工作,而read_commited和repeatable_read的區別不同就在于它們生成的ReadView的策略不同

對于使用read_commited和repeatable_read隔離級別的事務來說,都必須保證讀到已經提交了的事務修改過的記錄,也就是說假如另一個事務已經修改了記錄但未提交,是不能直接讀取最新版本的記錄的

核心問題就是:需要判斷一下,版本鏈中哪個版本是當前事務可見的

為此InnoDB提出了一個ReadView的概念,這個ReadView中有一個id列表,trx_ids來存儲系統中當前活躍著的讀寫事務,也就是begin了但是還未commit或rollback的事務

流程說明:

  • 獲取事務自己的版本號,即事務ID
  • 獲取Read View
  • 查詢得到的數據,然后Read View中的事務版本號進行比較。
  • 如果不符合Read View的可見性規則, 即就需要Undo log中歷史快照;
  • 最后返回符合規則的數據
  • 演示說明:

    提交了trx_id是2的記錄后,接著新建trx_id為3的事務,修改name的值,但是事務還沒有提交

    update user set name = '肉蟹寶 2 ' where id = 1

    則此時的版本鏈是:

    顯然,此時的trx_ids為[3]

    如果另一個事務查詢id為1的記錄,因為trx_ids當前只有trx_id為3的事務,而trx_ids的意義是記錄未完成的事務。在這里,事務未完成,所以該條記錄不可見,繼續查詢下一條,結果返回肉蟹寶1

    此時我把trx_id為3的事務提交了,并且新建了一個trx_id為4的事務,修改name,且不提交事務

    update user set name = '肉蟹寶 3 ' where id = 1

    這時的版本鏈就是:

    read-committed —— 每次查詢數據前都生成一個 ReadView

    trx_ids 將更新為[ 4 ],版本鏈通過 trx_id 對比查找到的結果就是肉蟹寶2

    repeatable-read —— 在第一次查詢數據時生成一個 ReadView,之后的讀都復用之前的。

    不會有重建的 ReadView , trx_ids 還是 [ 3 ],MySQL 認為事務3未完成,所以 select 的結果是肉蟹寶1。第2次 select 結果和第1次一樣,所以叫可重復讀。

    小結

    從上邊的描述中我們可以看出來,所謂的MVCC--多版本并發控制指的就是在使用read-commited、repeatable-read這兩種隔離級別的事務在執行select操作時,訪問記錄的版本鏈的過程。這樣子就可以使不同的事務的讀-寫、寫-讀作并發執行,從而提升系統性能。

    read-commited、repeatable-read這兩個隔離級別的很大一個不同就是:生成ReadView的時機不同

    read-commited 在每一次進行select操作時都會生成一個ReadView,而repeatable-read只在第一次進行普通select操作時生成一個ReadView,之后的查詢操作都重復使用這個ReadView

    參考與感謝:

    深入理解MYSQL的MVCC機制

    javaguide

    總結

    以上是生活随笔為你收集整理的什么是MVCC,一文搞懂MySQL的MVCC机制的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。