国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > MySQL > 正文

MySQL InnoDB之MVCC原理是啥

2024-07-24 12:33:08
字體:
來源:轉載
供稿:網友
  MVCC全稱Multi-Version Concurrency Control,即多版本并發控制,主要是為了提高數據庫的并發性能。同一行數據平時發生讀寫請求時,會上鎖阻塞住。但MVCC用更好的方式去處理讀—寫請求,做到在發生讀—寫請求沖突時不用加鎖。這個讀是指的快照讀,而不是當前讀,當前讀是一種加鎖操作,是悲觀鎖。那它到底是怎么做到讀—寫不用加鎖的,快照讀和當前讀是指什么?我們后面都會學到。
 
  trx_id:每次一個事務對某條聚簇索引記錄進行改動時,都會把該事務的事務id賦值給trx_id隱藏列。
  roll_pointer:每次對某條聚簇索引記錄進行改動時,都會把舊的版本寫入到undo日志中,然后這個隱藏列就相當于一個指針,可以通過它來找到該記錄修改前的信息。
  為了說明這個問題,我們創建一個演示表:
 
  CREATE TABLE `teacher` (
    `number` int(11) NOT NULL,
    `name` varchar(100) DEFAULT NULL,
    `domain` varchar(100) DEFAULT NULL,
    PRIMARY KEY (`number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8
  然后向這個表里插入一條數據:
 
  mysql> insert into teacher values(1, 'J', 'Java');Query OK, 1 row affected (0.01 sec)
  現在里的數據就是這樣的:
 
  mysql> select * from teacher;
  +--------+------+--------+
  | number | name | domain |
  +--------+------+--------+
  |      1 | J    | Java   |
  +--------+------+--------+
  1 row in set (0.00 sec)
 
  對該記錄每次更新后,都會將舊值放到一條undo日志中,就算是該記錄的一個舊版本,隨著更新次數的增多,所有的版本都會被roll_pointer屬性連接成一個鏈表,我們把這個鏈表稱之為版本鏈,版本鏈的頭節點就是當前記錄最新的值。另外,每個版本中還包含生成該版本時對應的事務id。于是可以利用這個記錄的版本鏈來控制并發事務訪問相同記錄的行為,那么這種機制就被稱之為多版本并發控制(Mulit-Version Concurrency Control MVCC)。
 
  ReadView
  對于使用READ UNCOMMITTED隔離級別的事務來說,由于可以讀到未提交事務修改過的記錄,所以直接讀取記錄的最新版本就好了。
 
  對于使用SERIALIZABLE隔離級別的事務來說,InnoDB使用加鎖的方式來訪問記錄。
 
  對于使用READ COMMITTED和REPEATABLE READ隔離級別的事務來說,都必須保證讀到已經提交了的事務修改過的記錄,也就是說假如另一個事務已經修改了記錄但是尚未提交,是不能直接讀取最新版本的記錄的,核心問題就是:READ COMMITTED和REPEATABLE READ隔離級別在不可重復讀和幻讀上的區別,這兩種隔離級別關鍵是需要判斷一下版本鏈中的哪個版本是當前事務可見的。
 
  為此,InnoDB提出了一個ReadView的概念,這個ReadView中主要包含4個比較重要的內容:
 
  m_ids:表示在生成ReadView時當前系統中活躍的讀寫事務的事務id列表。
  min_trx_id:表示在生成ReadView時當前系統中活躍的讀寫事務中最小的事務id,也就是m_ids中的最小值。
  max_trx_id:表示生成ReadView時系統中應該分配給下一個事務的id值。注意max_trx_id并不是m_ids中的最大值,事務id是遞增分配的。比方說現在有id為1,2,3這三個事務,之后id為3的事務提交了。那么一個新的讀事務在生成ReadView時,m_ids就包括1和2,min_trx_id的值就是1,max_trx_id的值就是4。
  creator_trx_id:表示生成該ReadView的事務的事務id。
  有了這個ReadView,這樣在訪問某條記錄時,只需要按照下邊的步驟判斷記錄的某個版本是否可見:
 
  如果被訪問版本的trx_id屬性值與ReadView中的creator_trx_id值相同,意味著當前事務在訪問它自己修改過的記錄,所以該版本可以被當前事務訪問。
  如果被訪問版本的trx_id屬性值小于ReadView中的min_trx_id值,表明生成該版本的事務在當前事務生成ReadView前已經提交,所以該版本可以被當前事務訪問。
  如果被訪問版本的trx_id屬性值大于或等于ReadView中的max_trx_id值,表明生成該版本的事務在當前事務生成ReadView后才開啟,所以該版本不可以被當前事務訪問。
  如果被訪問版本的trx_id屬性值在ReadView的min_trx_id和max_trx_id之間(min_trx_id <= trx_id < max_trx_id),那就需要判斷一下trx_id屬性值是不是在m_ids列表中,如果在,說明創建ReadView時生成該版本的事務還是活躍的,事務還沒提交,該版本不可以被訪問;如果不在,說明創建ReadView時生成該版本的事務已經被提交,該版本可以被訪問。
  如果某個版本的數據對當前事務不可見的話,那就順著版本鏈找到下一個版本的數據,繼續按照上邊的步驟判斷可見性,依此類推,直到版本鏈中的最后一個版本。如果最后一個版本也不可見的話,那么就意味著該條記錄對該事務完全不可見,查詢結果就不包含該記錄。

(編輯:武林網)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 德昌县| 新巴尔虎左旗| 阿图什市| 交城县| 田东县| 巫溪县| 台前县| 榆中县| 利辛县| 长岛县| 许昌市| 长春市| 南陵县| 芦溪县| 天津市| 防城港市| 万盛区| 无为县| 沅陵县| 渭源县| 平和县| 普兰县| 和顺县| 阿拉善盟| 哈尔滨市| 峨眉山市| 遵义市| 永善县| 恩平市| 夹江县| 稻城县| 三台县| 耒阳市| 紫金县| 绥芬河市| 黎川县| 岢岚县| 孟津县| 南开区| 山东| 德兴市|