最近公司的技術分享一直在分享 mysql 事務,隔離級別,鎖和 MVCC
方面的知識,但是都是基於單個點進行分析,沒有一步一步來闡述,所以在這裏我整理了一下 mysql 由 ACID 到 MVCC 這一塊的知識準備分享給大家。
咱們開門見山先談 事務
- 首先思考事務有什麼作用?
- 事務是爲了保證數據庫中數據的完整性和一致性
- 事務的四個基本要素 ACID ?這四要素是怎麼實現的?
- 原子性
Atomicity
- 原子性通過 Innodb
undo log
即回滾日誌實現
- 原子性通過 Innodb
- 一致性
Consistency
- 一致性通過
lock
鎖來實現
- 一致性通過
- 隔離性
Isolation
- 隔離性通過
lock
鎖和MVCC
來實現
- 隔離性通過
- 持久性
Durability
- 持久性通過 Innodb
redo log
即重寫日誌實現 ,和doublewrite
兩次寫技術來實現
- 持久性通過 Innodb
- 原子性
現在我們開始談 隔離級別
- 什麼是隔離級別 ?
- 併發事務之間相互影響的程度,隔離級別越高影響程度就越低
- 併發事務會造成的問題
- 髒讀:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據
- 不可重複讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A多次讀取同一數據時,結果 不一致。
- 幻讀:系統管理員A將數據庫中所有學生的成績從具體分數改爲ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀
- 隔離級別的種類
read-uncommitted
讀未提交- 讀數據時不加鎖,寫數據時加行級共享鎖
read-committed
不可重複讀- 讀數據使用
MVCC
,寫數據加行級排它鎖
- 讀數據使用
repeatable-read
可重複讀- 讀數據使用
MVCC
,寫數據加行級排它鎖和gap、next-key lock
- 如果是用到了主鍵的話加鎖
- 讀數據使用
serializable
串行化- 讀數據加表級共享鎖,寫數據加表級排它鎖
在 Mysql 的併發控制中我們常常需要使用到 鎖 和 MVCC,那麼這兩者的使用場景有什麼區別呢,爲什麼有了鎖還要引入 MVCC 呢?下面我將爲大家娓娓道來這兩者使用上的區別
基於鎖的併發控制
LBCC
(Lock-Based Concurrent Control) 即基於鎖的併發控制- Mysql 的鎖由 共享鎖(讀鎖) 和 排它鎖(寫鎖) 組成
- 按粒度也可以分爲表鎖和行鎖
- 加鎖和解鎖遵循
2PL
即 兩階段鎖原則 2PL
就是將加鎖/解鎖分爲兩個完全不相交的階段。加鎖階段:只加鎖,不放鎖。解鎖階段:只放鎖,不加鎖- 若所有事務均遵守兩段鎖協議,則這些事務的所有交叉調度都是可串行化1的
多版本的併發控制
MVCC
即 (Multi-Version Concurrency Control) 多版本的併發控制協議MVCC
最大的好處可以概括爲讀不加鎖,讀寫不衝突MVCC
併發控制中,讀操作可以分成兩類:快照讀(snapshot read)
與當前讀(current read)
。- 快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。
- 簡單的select操作,屬於快照讀,不加鎖。
SELECT * FROM user WHERE ?
- 簡單的select操作,屬於快照讀,不加鎖。
- 當前讀,讀取的是記錄的最新版本,並且,當前讀返回的記錄,都會加上鎖,保證其他事務不會再併發修改這條記錄
- 特殊的讀操作,插入/更新/刪除操作,屬於當前讀,需要加鎖。
- 特殊讀 (加鎖讀)
SELECT * FROM user WHERE ? LOCK IN SHARE MODE;
- 插入/更新/刪除
SELECT * FROM user WHERE ? FOR UPDATE;
INSERT INTO user VALUES (…);
UPDATE user SET ? WHERE ?;
DELETE FROM user WHERE ?;
- 特殊讀 (加鎖讀)
- 特殊的讀操作,插入/更新/刪除操作,屬於當前讀,需要加鎖。
- 快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。
當且僅當某組併發事務的交叉調度產生的結果和這些事務的某一串行調度的結果相同,則稱這個交叉調度是可串行化 ↩︎