面試官:什么是快照讀?什么是當(dāng)前讀?有什么區(qū)別?
大家好,我是君哥。
使用 MySQL 時,我們經(jīng)常會聽到快照讀、當(dāng)前讀這樣的概念,今天我們就來聊一聊快照讀、當(dāng)前讀。
快照讀和當(dāng)前讀,主要區(qū)別在于是否讀取到最新提交的數(shù)據(jù),是否需要加鎖,它們對數(shù)據(jù)庫的并發(fā)性能有所不同。
1.快照讀
快照讀,讀取的是數(shù)據(jù)的快照,通過讀視圖,提供非阻塞讀取,代替加鎖機(jī)制,提高并發(fā)性能。
我們知道,MySQL 事務(wù)隔離級別有 4 個:
- 串行化(Serializable):事務(wù)對數(shù)據(jù)讀寫都是串行化的。
- 可重復(fù)讀(Repeatable Read):事務(wù)執(zhí)行過程中,多次讀取同一行數(shù)據(jù),讀取結(jié)果一致。MySQL 默認(rèn)隔離級別就是可重復(fù)讀。
- 讀已提交數(shù)據(jù)(Read Committed):事務(wù)執(zhí)行過程中,如果有其他事務(wù)修改了數(shù)據(jù)并且提交事務(wù),當(dāng)前事務(wù)可以讀取到最新提交的數(shù)據(jù)。
- 讀未提交數(shù)據(jù)(Read Uncommitted):事務(wù)執(zhí)行過程中,可以讀取到其他事務(wù)未提交的數(shù)據(jù)。
其中可重復(fù)讀和讀已提交數(shù)據(jù),依托 MVCC(多版本并發(fā)控制)實(shí)現(xiàn)了快照讀。
不同的是,可重復(fù)讀是在事務(wù)開始時創(chuàng)建視圖,每個事務(wù)就使用一個快照,所以多次讀取結(jié)果是一樣的,看不到新提交的數(shù)據(jù)。而讀已提交是在每次語句執(zhí)行前創(chuàng)建新的視圖,所以能讀取到新提交的數(shù)據(jù)。
比如有一張表 t_acct,其中有 id,account、amount 三個字段,在一個事務(wù)中有一條 SQL 語句被執(zhí)行了 3 次:
select amount from t_acct where id=10;在可重復(fù)讀隔離級別下,讀取到的數(shù)據(jù)如下:
圖片
在讀已提交隔離級別下,讀取到的數(shù)據(jù)如下圖:
圖片
總結(jié),快照讀的特點(diǎn)就是讀取視圖數(shù)據(jù),不加鎖,非阻塞,執(zhí)行 SQL 語句一般是簡單查詢:
SELECT xxx FROM table WHERE 條件2.當(dāng)前讀
跟快照讀對應(yīng)的就是當(dāng)前讀,特點(diǎn)是讀取數(shù)據(jù)最新提交的版本,在讀取時會對數(shù)據(jù)進(jìn)行加鎖,以防止其他事務(wù)并發(fā)修改這條數(shù)據(jù)。優(yōu)點(diǎn)是強(qiáng)一致,可以讀取到數(shù)據(jù)最新版本,防止丟失更新。缺點(diǎn)是有加鎖帶來的阻塞和性能損耗。
當(dāng)前讀涉及的 SQL 如下:
SELECT xxx FROMTABLELOCKINSHAREMODE (共享鎖);
SELECT xxx FROMTABLEFORUPDATE (排它鎖)
UPDATETABLEset xxx (更新前先加排它鎖)
DELETEFROMTABLEWHERE xxx (刪除前先加排它鎖)
INSERTINTOTABLE xxx (加排它鎖)3.總結(jié)
當(dāng)前讀和快照讀的區(qū)別總結(jié)如下:
差異點(diǎn) | 快照讀 | 當(dāng)前讀 |
數(shù)據(jù)版本 | 基于快照,不一定最新 | 最新提交版本 |
是否加鎖 | 不加 | 加鎖 |
一致性 | 可能有不一致情況 | 強(qiáng)一致 |
并發(fā)性 | 強(qiáng) | 可能有阻塞 |
實(shí)現(xiàn)原理 | MVCC | 數(shù)據(jù)庫鎖 |
適用隔離級別 | 可重復(fù)讀、讀已提交 | 全部 |
對于簡單的數(shù)據(jù)查詢,不要求查詢最新提交數(shù)據(jù),可以考慮使用快照讀。如果要求讀取到最新提交數(shù)據(jù),那就考慮使用當(dāng)前讀。






























