溫故知新-Mysql鎖&事務&MVCC



鎖概述

鎖是計算機協調多個進程或線程併發訪問某一資源的機制(避免爭搶)。 在數據庫中,除傳統的計算資源(如 CPU、RAM、I/O 等)的爭用之外,數據也是一種供許多用戶共享的資源。如 何保證數據併發訪問的一致性、有效性是全部數據庫必須解決的一個問題,鎖衝突也是影響數據庫併發訪問性能的 一個重要因素。從這個角度來講,鎖對數據庫而言顯得尤爲重要,也更加複雜sql

鎖分類

  • 從對數據操做的粒度分

1) 表鎖:操做時,會鎖定整個表。 2) 行鎖:操做時,會鎖定當前操做行。數據庫

  • 從對數據操做的類型分

1) 讀鎖(共享鎖):針對同一份數據,多個讀操做能夠同時進行而不會互相影響 2) 寫鎖(排它鎖):當前操做沒有完成以前,它會阻斷其餘寫鎖和讀鎖安全

  • Mysql 鎖

相對其餘數據庫而言,MySQL的鎖機制比較簡單,其最顯著的特色是不一樣的存儲引擎支持不一樣的鎖機制。下表中羅 列出了各存儲引擎對鎖的支持狀況: 併發

鎖

  • MySQL這3種鎖的特性可大體概括以下 :高併發

    • 表鎖

    偏向MyISAM 存儲引擎,開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。性能

    • 行鎖

    偏向InnoDB 存儲引擎,開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。線程

    • 頁面鎖

    開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常設計

MyISAM 表鎖

  • 對MyISAM 表的讀操做,不會阻塞其餘用戶對同一表的讀請求,但會阻塞對同一表的寫請求;
  • 對MyISAM 表的寫操做,則會阻塞其餘用戶對同一表的讀和寫操做;

簡而言之,就是讀鎖會阻塞寫,可是不會阻塞讀。而寫鎖,則既會阻塞讀,又會阻塞寫。3d

  • 此外,MyISAM 的讀寫鎖調度是寫優先,這也是MyISAM不適合作寫爲主的表的存儲引擎的緣由。由於寫鎖後,其餘線程不能作任何操做,大量的更新會使查詢很可貴到鎖,從而形成永遠阻塞。

InnoDB 行鎖

  • 行鎖特色 :偏向InnoDB 存儲引擎,開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
  • InnoDB 與 MyISAM 的最大不一樣有兩點:一是支持事務;二是 採用了行級鎖。

事務及其ACID屬性

  • 事務是由一組SQL語句組成的邏輯處理單元,事務具備如下4個特性,簡稱爲事務ACID屬性。
    事務ACID屬性
  • 併發事務處理帶來的問題
    在這裏插入圖片描述
  • 事務隔離級別
    • 爲了解決上述提到的事務併發問題,數據庫提供必定的事務隔離機制來解決這個問題。數據庫的事務隔離越嚴格,併發反作用越小,但付出的代價也就越大,由於事務隔離實質上就是使用事務在必定程度上「串行化」 進行,這顯然 與「併發」 是矛盾的。
    • 數據庫的隔離級別有4個,由低到高依次爲Read uncommitted、Read committed、Repeatable read、 Serializable,這四個級別能夠逐個解決髒寫、髒讀、不可重複讀、幻讀這幾類問題。
      在這裏插入圖片描述
      Mysql 的數據庫的默認隔離級別爲 Repeatable read;

InnoDB 的行鎖模式

InnoDB 實現瞭如下兩種類型的行鎖。指針

  • 共享鎖(S):又稱爲讀鎖,簡稱S鎖,共享鎖就是多個事務對於同一數據能夠共享一把鎖,都能訪問到數據,可是隻能讀不能修改。
  • 排他鎖(X):又稱爲寫鎖,簡稱X鎖,排他鎖就是不能與其餘鎖並存,如一個事務獲取了一個數據行的排他鎖,其餘事務就不能再獲取該行的其餘鎖,包括共享鎖和排他鎖,可是獲取排他鎖的事務是能夠對數據就行讀取和修改。

對於UPDATE、DELETE和INSERT語句,InnoDB會自動給涉及數據集加排他鎖(X);對於普通SELECT語句,InnoDB不會加任何鎖;

  • 無索引行鎖升級爲表鎖

若是不經過索引條件檢索數據,那麼InnoDB將對錶中的全部記錄加鎖,實際效果跟表鎖同樣。

  • 間隙鎖危害

當咱們用範圍條件,而不是使用相等條件檢索數據,並請求共享或排他鎖時,InnoDB會給符合條件的已有數據進行加鎖; 對於鍵值在條件範圍內但並不存在的記錄,叫作 "間隙(GAP)" ,InnoDB也會對這個 "間隙" 加鎖,這種鎖機制就是所謂的間隙鎖(Next-Key鎖)

注意

  • InnoDB存儲引擎因爲實現了行級鎖定,雖然在鎖定機制的實現方面帶來了性能損耗可能比表鎖會更高一些,可是在總體併發處理能力方面要遠遠因爲MyISAM的表鎖的。當系統併發量較高的時候,InnoDB的總體性能和MyISAM相比就會有比較明顯的優點。

  • 可是,InnoDB的行級鎖一樣也有其脆弱的一面,當咱們使用不當的時候,可能會讓InnoDB的總體性能表現不只不 能比MyISAM高,甚至可能會更差。

  1. 儘量讓全部數據檢索都能經過索引來完成,避免無索引行鎖升級爲表鎖。
  2. 合理設計索引,儘可能縮小鎖的範圍
  3. 儘量減小索引條件,及索引範圍,避免間隙鎖
  4. 儘可能控制事務大小,減小鎖定資源量和時間長度
  5. 儘可以使用低級別事務隔離(可是須要業務層面知足需求)

MVCC

MVCC (Multiversion Concurrency Control) 中文全程叫多版本併發控制,是現代數據庫(包括 MySQL、Oracle、PostgreSQL 等)引擎實現中經常使用的處理讀寫衝突的手段,目的在於提升數據庫高併發場景下的吞吐性能。

  • 如此一來不一樣的事務在併發過程當中,SELECT 操做能夠不加鎖而是經過 MVCC 機制讀取指定的版本歷史記錄,並經過一些手段保證保證讀取的記錄值符合事務所處的隔離級別,從而解決併發場景下的讀寫衝突。

InnoDB 中的 MVCC

  • InnoDB MVCC 實現原理的關鍵

一、事務版本號 二、表的隱藏列。 三、undo log 四、 read view

InnoDB 中 MVCC 的實現方式爲:每一行記錄都有兩個隱藏列:DATA_TRX_ID、DATA_ROLL_PTR(若是沒有主鍵,則還會多一個隱藏的主鍵列)。

在這裏插入圖片描述

  • DATA_TRX_ID

記錄最近更新這條行記錄的事務 ID,大小爲 6 個字節

  • DATA_ROLL_PTR

表示指向該行回滾段(rollback segment)的指針,大小爲 7 個字節,InnoDB 即是經過這個指針找到以前版本的數據。該行記錄上全部舊版本,在 undo 中都經過鏈表的形式組織。

  • DB_ROW_ID

行標識(隱藏單調自增 ID),大小爲 6 字節,若是表沒有主鍵,InnoDB 會自動生成一個隱藏主鍵,所以會出現這個列。另外,每條記錄的頭信息(record header)裏都有一個專門的 bit(deleted_flag)來表示當前記錄是否已經被刪除。

  • 組織 Undo Log 鏈
    在這裏插入圖片描述
  • 如何實現一致性讀 —— ReadView InnoDB 爲了解決這個問題,設計了 ReadView(可讀視圖)的概念。 ReadView :每一個 SELECT 語句開始時,會生成一致性視圖,ReadView 中是當前活躍的事務 ID 列表,稱之爲 m_ids,其中最小值爲 up_limit_id,最大值爲low_limit_id,事務 ID 是事務開啓時 InnoDB 分配的,其大小決定了事務開啓的前後順序,所以咱們能夠經過 ID 的大小關係來決定版本記錄的可見性;
  1. 若是被訪問版本的 trx_id 小於 m_ids 中的最小值 up_limit_id,說明生成該版本的事務在 ReadView 生成前就已經提交了,因此該版本能夠被當前事務訪問。
  2. 若是被訪問版本的 trx_id 大於 m_ids 列表中的最大值 low_limit_id,說明生成該版本的事務在生成 ReadView 後才生成,因此該版本不能夠被當前事務訪問。須要根據 Undo Log 鏈找到前一個版本,而後根據該版本的 DB_TRX_ID 從新判斷可見性。
  3. 若是被訪問版本的 trx_id 屬性值在 m_ids 列表中最大值和最小值之間(包含),那就須要判斷一下 trx_id 的值是否是在 m_ids 列表中。若是在,說明建立 ReadView 時生成該版本所屬事務仍是活躍的,所以該版本不能夠被訪問,須要查找 Undo Log 鏈獲得上一個版本,而後根據該版本的 DB_TRX_ID 再從頭計算一次可見性;若是不在,說明建立 ReadView 時生成該版本的事務已經被提交,該版本能夠被訪問。
  4. 此時通過一系列判斷咱們已經獲得了這條記錄相對 ReadView 來講的可見結果。此時,若是這條記錄的 delete_flag 爲 true,說明這條記錄已被刪除,不返回。不然說明此記錄能夠安全返回給客戶端。

參考

MySQL InnoDB MVCC 機制的原理及實現


你的鼓勵是我創做的最大動力

打賞
相關文章
相關標籤/搜索