mysql中快照讀和當(dāng)前讀操作方法
前言
在 MySQL InnoDB 存儲(chǔ)引擎中,快照讀(Snapshot Read) 和 當(dāng)前讀(Current Read) 是兩種核心的讀操作模式,二者的設(shè)計(jì)目標(biāo)、實(shí)現(xiàn)方式、加鎖行為和適用場景截然不同,其中快照讀是 MVCC 機(jī)制的核心體現(xiàn),當(dāng)前讀則依賴鎖機(jī)制保證數(shù)據(jù)一致性。
一、快照讀(Snapshot Read)
- 定義
快照讀是指讀取數(shù)據(jù)的歷史版本(快照),而非數(shù)據(jù)的最新版本,是 InnoDB 實(shí)現(xiàn) MVCC 多版本并發(fā)控制的核心讀方式。 - 核心特征
- 無鎖讀?。鹤x取時(shí)不加任何行鎖 / 表鎖,完全避免鎖競爭,讀寫互不阻塞(讀不阻塞寫,寫不阻塞讀);
- 依賴 MVCC:通過「行版本鏈 + Read View」判斷數(shù)據(jù)可見性,只讀取符合當(dāng)前事務(wù)隔離級(jí)別的歷史版本;
- 版本一致性:在不同隔離級(jí)別下,快照讀的版本可見性規(guī)則不同(如可重復(fù)讀級(jí)別下,事務(wù)內(nèi)多次快照讀復(fù)用同一個(gè) Read View,保證結(jié)果一致)。
- 適用場景
所有普通的 SELECT 語句(無特殊鎖提示)都屬于快照讀,例如:
SELECT * FROM user WHERE id = 1; SELECT name FROM user WHERE age > 20;
- 典型行為(以可重復(fù)讀為例)
假設(shè)事務(wù) A 執(zhí)行快照讀讀取 id=1 的數(shù)據(jù)(值為 Tom),此時(shí)事務(wù) B 修改該數(shù)據(jù)為 Jerry 并提交,但事務(wù) A 后續(xù)的快照讀仍會(huì)讀取到 Tom(因?yàn)閺?fù)用第一次生成的 Read View,看不到事務(wù) B 提交的新版本)。
二、當(dāng)前讀(Current Read)
- 定義
當(dāng)前讀是指讀取數(shù)據(jù)的最新版本,且讀取時(shí)會(huì)對目標(biāo)數(shù)據(jù)加鎖(行鎖 / 間隙鎖),防止其他事務(wù)修改該數(shù)據(jù),保證讀取和后續(xù)操作的原子性。 - 核心特征
- 加鎖讀取:讀取最新版本的同時(shí),會(huì)為數(shù)據(jù)加鎖(排他鎖 / 共享鎖),阻塞其他事務(wù)的寫操作或當(dāng)前讀操作;
- 不依賴 MVCC:直接讀取最新版本,無視版本鏈和 Read View;
- 強(qiáng)一致性:保證讀取到的是數(shù)據(jù)的最新狀態(tài),適用于需要精準(zhǔn)操作最新數(shù)據(jù)的場景。
- 適用場景
以下操作均屬于當(dāng)前讀:
| 操作類型 | 示例 | 加鎖類型 |
|---|---|---|
| 加鎖的SELECT | SELECT * FROM user WHERE id = 1 FOR UPDATE; | 排他鎖(X 鎖),阻塞其他寫操作和 FOR UPDATE 操作 |
| 加鎖的 SELECT | SELECT * FROM user WHERE id = 1 LOCK IN SHARE MODE; | 共享鎖(S 鎖),阻塞其他排他鎖操作,允許共享鎖操作 |
| 寫操作(隱式當(dāng)前讀) | INSERT INTO user (name) VALUES (‘Tom’); | 排他鎖(插入行加鎖) |
| 寫操作(隱式當(dāng)前讀) | UPDATE user SET name = ‘Jerry’ WHERE id = 1; | 先對目標(biāo)行加排他鎖,再讀取最新版本并修改 |
| 寫操作(隱式當(dāng)前讀) | DELETE FROM user WHERE id = 1; | 先對目標(biāo)行加排他鎖,再讀取最新版本并標(biāo)記刪除 |
- 典型行為
假設(shè)事務(wù) A 執(zhí)行 SELECT * FROM user WHERE id = 1 FOR UPDATE;(當(dāng)前讀),此時(shí)會(huì)讀取 id=1 的最新版本并加排他鎖:
- 事務(wù) B 若執(zhí)行 UPDATE user SET name = ‘Jack’ WHERE id = 1;,會(huì)被阻塞,直到事務(wù) A 提交 / 回滾;
- 事務(wù) B 若執(zhí)行普通 SELECT(快照讀),仍可讀取到歷史版本(不受當(dāng)前讀鎖的影響)。
三、快照讀 vs 當(dāng)前讀 核心對比
| 維度 | 快照讀 | 當(dāng)前讀 |
|---|---|---|
| 讀取數(shù)據(jù)版本 | 歷史版本(快照) | 最新版本 |
| 加鎖行為 | 無鎖 | 加行鎖 / 間隙鎖(排他 / 共享) |
| 依賴機(jī)制 MVCC | (版本鏈 + Read View) | 鎖機(jī)制(行鎖、Next-Key Lock) |
| 并發(fā)特性 | 讀寫不阻塞,性能高 | 讀阻塞寫(排他鎖),寫阻塞讀,性能較低 |
| 隔離性保證 | 可重復(fù)讀 / 讀已提交(依賴隔離級(jí)別) | 串行化級(jí)別的強(qiáng)一致性 |
| 適用場景 | 普通查詢,追求并發(fā)性能 | 精準(zhǔn)操作最新數(shù)據(jù)(如更新 / 刪除前校驗(yàn)、加鎖查詢) |
| 典型語句 | SELECT …(無鎖提示 | ) SELECT … FOR UPDATE/INSERT/UPDATE/DELETE |
四、關(guān)鍵補(bǔ)充說明
- 隔離級(jí)別的影響:
- 讀未提交(READ UNCOMMITTED):無快照讀,直接讀取最新版本(等價(jià)于當(dāng)前讀),會(huì)出現(xiàn)臟讀;
- 串行化(SERIALIZABLE):快照讀被降級(jí)為當(dāng)前讀(加鎖),所有讀操作都加鎖,完全串行執(zhí)行。
- 寫操作的隱式當(dāng)前讀:
- INSERT/UPDATE/DELETE 執(zhí)行時(shí),會(huì)先觸發(fā)「當(dāng)前讀」讀取最新版本的數(shù)據(jù),再執(zhí)行寫操作,確保修改的是最新數(shù)據(jù),避免丟失更新。
- 鎖的范圍:
- 當(dāng)前讀的加鎖范圍不僅包含匹配的行,還可能包含間隙(Next-Key Lock),防止幻讀(可重復(fù)讀級(jí)別下)。
總結(jié)
- 快照讀是 InnoDB 高并發(fā)的核心,通過 MVCC 實(shí)現(xiàn)無鎖讀,犧牲 “最新性” 換取性能;
- 當(dāng)前讀是保證數(shù)據(jù)強(qiáng)一致性的手段,通過加鎖讀取最新版本,犧牲 “并發(fā)性” 換取準(zhǔn)確性;
- 日常開發(fā)中,普通查詢用快照讀即可,需要精準(zhǔn)操作最新數(shù)據(jù)(如秒殺、庫存扣減)時(shí),需用當(dāng)前讀(如 SELECT … FOR UPDATE)。
相關(guān)文章
mysql無法成功啟動(dòng)服務(wù)的解決方法(通俗易懂!)
Mysql是我們使用數(shù)據(jù)庫時(shí)需要用到的服務(wù),但是在使用過程中常常遇到服務(wù)無法啟動(dòng)的問題,下面這篇文章主要給大家介紹了關(guān)于mysql無法成功啟動(dòng)服務(wù)的解決方法,需要的朋友可以參考下2023-02-02
通過實(shí)例判斷mysql update是否會(huì)鎖表
這篇文章主要介紹了通過實(shí)例判斷mysql update是否會(huì)鎖表,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
從原理到實(shí)踐詳解MySQL大批量數(shù)據(jù)導(dǎo)入的性能優(yōu)化指南
在日常運(yùn)維或數(shù)據(jù)遷移場景中,MySQL大批量數(shù)據(jù)導(dǎo)入慢的問題經(jīng)常困擾著開發(fā)者和運(yùn)維人員,本文將為大家詳細(xì)介紹三大核心優(yōu)化方案,幫你把數(shù)據(jù)導(dǎo)入效率提升10倍以上2025-12-12
mysql分區(qū)表學(xué)習(xí)之日期分區(qū)
這篇文章主要給大家介紹了關(guān)于mysql分區(qū)表學(xué)習(xí)之日期分區(qū)的相關(guān)資料,分區(qū)是一種表的設(shè)計(jì)模式,通俗地講表分區(qū)是將一大表,根據(jù)條件分割成若干個(gè)小表,需要的朋友可以參考下2023-08-08
淺談MySQL安裝starting the server失敗的解決辦法
如果電腦是不是第一次安裝MySQL,一般會(huì)出現(xiàn)報(bào)錯(cuò)情況,starting the server失敗,通常是因?yàn)樯洗伟惭b的該軟件未清除干凈,本文就詳細(xì)的介紹一下解決方法,感興趣的可以了解一下2021-09-09
mysql出現(xiàn)Error performing load command的解決方法
一般就是數(shù)據(jù)庫表字段類型問題,大家參考下面的方法解決下2008-06-06
MySQL數(shù)據(jù)庫多表聯(lián)合查詢代碼示例
所謂聯(lián)合就是把多個(gè)表的記錄往一起合并,一起進(jìn)行查詢,也叫多表查詢,這篇文章主要給大家介紹了關(guān)于MySQL數(shù)據(jù)庫多表聯(lián)合查詢的相關(guān)資料,需要的朋友可以參考下2024-01-01

