MySql鎖與InnoDB引擎
阿新 • • 發佈:2020-03-21
## 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的事務