1. 程式人生 > >MySql鎖與InnoDB引擎

MySql鎖與InnoDB引擎

## MySql鎖與InnoDB引擎 > mysql的鎖是面試中很高頻問題,也是我們在日常開發中經常會遇到但是我們並沒有注意到的地方。我把我自己理解的鎖通過本篇博文分享出來,由於鎖需要結合事務來理解,本文只介紹鎖的基本概念,同樣為了理解事務會更加深刻,先介紹了InnoDB的一些基礎概念,也是記錄自己的學習,歡迎大家一起探討交流。 > > 下一篇:mysql的事務與mvcc ### 鎖的分類: ![]( http://q7dahrctq.bkt.clouddn.com/1584772737.jpg ) - 按照鎖的粒度來分 - 全域性鎖: 鎖的是整個database,類比一個庫為一棟大樓,那此時就是鎖的整棟樓的大門 - 表級鎖: 鎖的是某個table,類比一個表為大樓的某一層,此時鎖的就是某一層整層 - 行級鎖:鎖的是某一行資料,類比每行鎖的是某一層的某一間房間,此時鎖的是某一個房間 - 表鎖和行鎖的區別 - 表級鎖,開銷大,加鎖快,不會出現死鎖。鎖的粒度大。併發度低。 - 行級鎖,開銷小,加鎖慢,會出現死鎖,鎖的粒度小,併發度高。 ### 表級鎖: mysql的表級鎖有兩種:元資料鎖和表鎖。 表鎖的兩種形式: - 表共享讀鎖 - 表排它寫鎖 - 手動加表鎖 ``` sql lock table tableName read; ``` - 查看錶鎖情況 ``` sql show open tables; ``` - 刪除表鎖 ``` sql unlock tables; ``` 元資料鎖: - 5.5版本中引入了MDL,對一個表資料進行增刪改的時候,加MDL讀鎖;要對錶結構進行修改的時候,加MDL寫鎖。 ### 行級鎖 > mysql的行級鎖是有儲存引擎實現的,mysql現在預設的資料引擎為Innodb。本文主要介紹InnoDB的行鎖; > > InnoDB的行鎖是給索引項加鎖實現的,也就意味著只有使用索引檢索的資料才能使用行鎖,否則將使用表鎖。 #### 按照範圍來說 - 行鎖:鎖定表中的某一條記錄。 - 間隙鎖: - 鎖住索引記錄中間的值 - 鎖住第一個索引記錄前面的值或者最後一個索引後面的值 #### 按照功能來說 - 共享鎖,也叫做S鎖:允許一個事務去讀一行資料,阻止其他事務新增排它鎖,允許繼續新增共享鎖讀 - 排它鎖,也叫做X鎖:允許獲得排它鎖的事務更新資料,阻止其他事務新增讀共享鎖和新增排它鎖寫 > 對於InnoDB來說,會自動給增刪改語句新增排它鎖,X鎖。對於普通的查詢語句不會新增任何鎖。 #### 意向鎖 InnoDB同樣也實現了表級鎖,也就是意向鎖。意向鎖是mysql內部使用的,不需要使用者去幹預。 - 意向共享鎖,IS鎖:事務打算給資料行加共享鎖,事務在給一個數據行新增共享鎖前必須獲取該表的IS鎖。 - 意向排它鎖,IX鎖:事務打算給資料航加排它鎖,事務在給一個數據行新增排它鎖前必須獲取該表的IX鎖。 意向和行鎖可以共存,意向鎖的作用是為了提升全表更新資料時的效能提升,否則在更新全表時要檢索哪些資料行上有行鎖。 #### 間隙鎖 顧名思義,主要是在記錄之間新增鎖,不允許往間隙插入資料。比如id為 2 4,那此時使用間隙鎖就會鎖2 3 4 這三個,稍後在介紹事務的時候也會再次介紹間隙鎖,間隙鎖的主要作用就是為了解決幻讀問題。此處先了解一下。 #### 死鎖 mysql的死鎖和我們程式碼中死鎖理論是一樣的,不同的是,mysql指的是兩個不同的連線互相等待對方釋放鎖,才能釋放自己持有的資源,所以造成了死鎖。mysql中也有對死鎖的優化。我們稍後再具體說。 > 接下來我們開始介紹事務,上面只是簡單介紹了一下鎖的基本概念,鎖還有一部分內容需要結合事務來理解,所以稍後還有鎖的介紹。 > > 在我們介紹事務之前,我們先聊一下InnoDB的架構,事務中的一些部分會涉及到這部分的內容。 ### InnoDB的磁碟檔案 #### InnoDB的磁碟檔案 - 系統表空間 - 系統表空是一個共享的表空間 - 系統表空間包含資料字典、doule write buffer、change buffer、undo log的儲存區域,包含使用者在系統表建立的表結構和索引資料 - 使用者表空間 - 設定引數 innodb_file_per_table ,使用者就可以為每個基於InnoDB引擎的表建立一個獨立的使用者表空間,也就是.ibd檔案。 - 儲存該表的資料、索引等資訊。 #### InnoDB記憶體結構 - buff pool 緩衝池 - 資料是儲存於磁碟的,由於cpu速度和磁碟速度的差別,所以使用緩衝池提高整體效能。 - 通過innodb_buffer_pool_size可以設定緩衝池的大小,緩衝池的大小對效能也是有影響的。 - 緩衝池中緩衝的資料型別: - 索引頁 - 資料頁 - 儲存引擎工作時,需要以頁為單位將磁碟資料載入到記憶體中,資料頁和索引頁是頁型別中最重要的兩種型別 - undo頁:實現了mysql多版本的快照,可以理解為版本鏈。mvcc和回滾操作都涉及到了undo日誌。 - insert buffer:提高了對於非聚簇索引的插入效能 - 自適應雜湊索引 - InnoDB儲存的鎖資訊 - 資料字典資訊 #### 記憶體資料落盤 ![]( http://q7dahrctq.bkt.clouddn.com/623378-efed773073a9ab50.jpeg ) InnoDB資料落盤有圖可以看出來是通過兩種方式來實現的 - 髒頁資料落盤 - 預寫redo日誌 通過兩種方式來落盤,也可以理解為持久化到磁碟上。是為了保證數庫發生突然宕機,造成資料丟失。 髒頁落盤會產生IO並且是隨機寫入,耗時比較長。頻繁進行磁碟IO對效能損耗是非常大。並且資料的安全性得不到保障。如果在髒頁資料還沒來得及落盤或者落盤過程出現宕機,那麼資料就會丟失。 鑑於以上情況,mysql用雙保險完成資料的安全性,髒頁落盤是一種,另一種就是預寫redo 日誌,首先我們要知道redo 持久化到磁碟是順序寫入,順序寫入的速度要比隨機寫入要快,此時有朋友就會問,那髒頁落盤為什麼不採用順序寫入呢但? 順序寫入速度快的同時是會產生磁碟碎片的,磁碟碎片會大大浪費磁碟資源。 redo 日誌持久化的時機是在事務提交時寫入到磁碟的redo file中,此時髒頁資料並不一定完成了落盤,髒頁落盤是由checkPoint檢查點機制控制的,我們這裡不展開多說。 資料庫發生宕機的情況: - 髒頁資料未落盤,事務未提交,此時產生了資料丟失,我們都知道如果事務未提交換個角度來講這些資料丟失是正常的。 - 髒頁資料未落盤,事務已提交,此時redo log file已經有了資料,那麼重啟的時候mysql就會從redo log file中進行資料恢復。 > 有的朋友還會說,那redo log file的資料豈不是無限大? > ib_logfile0,ib_logfile1 這是rodo log 在我們磁碟上的命名,可以看到有兩個檔案,採用的迴圈寫入的方式,如果1滿了就寫入2,2滿了寫入1,這樣迴圈。 redo 日誌持久化到磁碟也是可以配置的,通過InnoDB的innodb_push_log_at_trx_commit來設定 1. 屬性值為0時,事務提交,不會對redo進行寫入操作,等待主執行緒按時寫入; 2. 屬性值為1時,事務提交,將資料寫入磁碟,確保不會出現資料丟失; 3. 屬性值為2時,事務提交,將資料寫入系統快取,讓檔案系統自己判斷什麼時候寫入磁碟。 預設值為1,一般也建議設定為1,會保證資料的安全性,並且只有為1的時候才會保證事務的一致性。 ****** ## 以上就是本篇博文的全部內容,感謝各位看官。歡迎提出問題一起交流探討。 > 下一篇:mysql的事務