最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Mysql是如何實(shí)現(xiàn)事務(wù)的以及相關(guān)擴(kuò)展知識總結(jié)

 更新時(shí)間:2026年05月27日 10:12:58   作者:小海獺敲代碼_KD  
在mysql中事務(wù)是一種機(jī)制、一個(gè)操作序列,是訪問和更新數(shù)據(jù)庫的程序執(zhí)行單元,下面這篇文章主要介紹了Mysql是如何實(shí)現(xiàn)事務(wù)的以及相關(guān)擴(kuò)展知識總結(jié)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

最近在準(zhǔn)備八股,整理了一些筆記,希望可以幫助到大家,有錯(cuò)誤也希望大家指出來,大家相互學(xué)習(xí)。

  • 實(shí)現(xiàn)事務(wù)靠四個(gè)核心組件:Redo log,Undo log,鎖,MVCC

為什么要有這四個(gè)東西?

數(shù)據(jù)庫事務(wù)要解決的核心矛盾是:

  • 既要快(高并發(fā))

  • 又要穩(wěn)(數(shù)據(jù)正確,宕機(jī)不丟)

如果只有一個(gè)最簡單的辦法:每次事務(wù)都直接改磁盤數(shù)據(jù)。那么:

  • 改完前宕機(jī) ——>數(shù)據(jù)損壞(需要原子性)

  • 同時(shí)改同一行 ——>混亂(需要隔離性)

  • 每次等磁盤——>太慢(需要性能)

于是四個(gè)組件進(jìn)行分工協(xié)作:

  • Redo Log(重做日志)保證持久性。事務(wù)提交時(shí),修改先寫到 redolog再寫磁盤數(shù)據(jù)頁。其實(shí)就是把本來寫磁盤的操作拆成兩步

    1. 先把修改內(nèi)容順序追加寫到 redo log 文件(這是順序?qū)?,極快),就認(rèn)為事務(wù)提交成功了。

    2. 后臺慢慢把數(shù)據(jù)頁刷到磁盤。

    • 就算寫數(shù)據(jù)頁時(shí)宕機(jī)了,重啟后通過重放redolog就能恢復(fù)數(shù)據(jù)。這就是經(jīng)典的WAL機(jī)制。

    • 總結(jié):用“寫日志代替隨機(jī)寫磁盤”,先保證提交速度,再異步刷盤。宕機(jī)后靠日志恢復(fù),實(shí)現(xiàn)了持久性。

  • Undo Log (回歸日志) 保證原子性。

  • 要解決的問題:事務(wù)執(zhí)行到一半要回滾,或者系統(tǒng)崩潰時(shí)要撤銷未提交的事務(wù),保證原子性(要么全做,要么全不做)。

    1. 每次修改數(shù)據(jù)前,先把舊值(和事務(wù) ID 等信息)存到 undo log 里。

    2. 如果事務(wù)要回滾,就按 undo log 反向操作,把數(shù)據(jù)改回去。

    3. 系統(tǒng)崩潰恢復(fù)時(shí),發(fā)現(xiàn)某些事務(wù)沒提交,也用 undo log 清理掉它們的修改。

    • undo log 保存了數(shù)據(jù)的歷史版本,這為后面的 MVCC 提供了基礎(chǔ)。

    • undo log 存了數(shù)據(jù)“修改前”的樣子,讓回滾和崩潰恢復(fù)能擦除未提交事務(wù)的痕跡

  • 鎖機(jī)制(行鎖、間隙鎖等等)保證隔離性。兩個(gè)事務(wù)同時(shí)改同一行,必須一個(gè)等另一個(gè)釋放鎖。InnoDB的鎖粒度精確到行級,還有間隙鎖防止幻讀。鎖是“硬隔離”,強(qiáng)制讓并發(fā)寫操作排隊(duì)執(zhí)行,保證數(shù)據(jù)同時(shí)只能被一個(gè)人改。

  • MVCC保證隔離性的讀寫并發(fā)。

    1. 利用 undo log 里保存的舊版本,讓每行數(shù)據(jù)在某一時(shí)刻都有多個(gè)“快照”。

    2. 每個(gè)事務(wù)在開始時(shí),會(huì)拿到一個(gè)“快照時(shí)間點(diǎn)”。

    3. 它讀數(shù)據(jù)時(shí),不是讀最新值,而是讀那個(gè)時(shí)間點(diǎn)之前已提交的最新版本(通過 undo log 版本鏈查找)。

    4. 這樣,一個(gè)事務(wù)在的時(shí)候,別的事務(wù)可以隨便寫(產(chǎn)生新版本),兩者互不干擾。

    • 總結(jié):MVCC 讓“讀”去讀歷史快照,“寫”去創(chuàng)建新版本。讀寫不再互相等待,極大提升了并發(fā)度。

  • 一致性不是單獨(dú)實(shí)現(xiàn)的,它是原子性、隔離性、持久性共同作用的結(jié)果。

    1. 原子性保證事務(wù)內(nèi)的操作要么全生效要么全取消,不會(huì)半途而廢。

    2. 隔離性保證多個(gè)事務(wù)并發(fā)時(shí),互相不會(huì)看到中間狀態(tài)或造成混亂。

    3. 持久性保證事務(wù)一旦提交,結(jié)果就不會(huì)丟失。

    這三者共同作用,確保了數(shù)據(jù)從一個(gè)正確的狀態(tài)(一致性)變到另一個(gè)正確的狀態(tài)。

擴(kuò)展知識

鎖的類型

Redo Log(重做日志)的工作原理

InnoDB修改數(shù)據(jù)時(shí)不會(huì)直接寫到磁盤上的數(shù)據(jù)頁,那樣隨機(jī)I/O太多,性能太差。他用的WAL策略:先把修改內(nèi)容順序追加到redo log(這是順序?qū)憳O快),后臺再找機(jī)會(huì)把數(shù)據(jù)頁刷到磁盤。

redo log 采用循環(huán)寫的方式,有兩個(gè)指針:write pos 表示當(dāng)前寫到哪了,checkpoint表示已經(jīng)刷盤的位置。兩個(gè)指針之間就是待刷盤的臟數(shù)據(jù)

+---+---+---+---+
| 0 | 1 | 2 | 3 |   redo log 文件組
+---+---+---+---+
    ^       ^
    |       |
checkpoint  write_pos

事務(wù)提交時(shí),redo log必須落盤,這個(gè)行為由innodb_flush_log_at_trx_commit控制:

  • 設(shè)成1:每次提交都刷盤,最安全但性能最差

  • 設(shè)成0:每秒刷一次,宕機(jī)可能丟1秒數(shù)據(jù)

  • 設(shè)成2:寫到操作系統(tǒng)緩存,Mysql掛了數(shù)據(jù)還在,機(jī)器掛了才丟

Undo Log(回滾日志)與版本鏈

每條數(shù)據(jù)都有兩個(gè)隱藏字段:trx_id記錄最后修改這條數(shù)據(jù)的事務(wù)ID,roll_pointer指向undolog里的上一個(gè)版本。多次修改就會(huì)形成一條版本鏈。 假設(shè)原始數(shù)據(jù)name='張三',事務(wù)100改成'李四',事務(wù)200又改成'王五':

當(dāng)前數(shù)據(jù)頁:name='王五', trx_id=200, roll_pointer →
    undo log:name='李四', trx_id=100, roll_pointer →
        undo log:name='張三', trx_id=0, roll_pointer=null

MVCC讀數(shù)據(jù)時(shí),根據(jù)事務(wù)的ReadView沿著版本鏈往回找,找到第一個(gè)自己能看見的版本??芍貜?fù)讀隔離級別下;ReadView在事務(wù)開始時(shí)生成一次,后面一直用這個(gè)。讀已提交隔離級別下,每次查詢都生成新的ReadView.

鎖的實(shí)現(xiàn)細(xì)節(jié)

InnoDB的行鎖實(shí)際上是加在索引上的,不是加在數(shù)據(jù)行上的。如果SQL沒走索引,就會(huì)鎖全表。

-- 假設(shè) id 是主鍵,name 無索引
begin;
update user set age = 20 where id = 1;     -- 只鎖 id=1 這一行
update user set age = 20 where name = '張三'; -- 鎖全表!
commit;

InnoDB有三種行鎖:

  • Record Lock(記錄鎖):鎖單條記錄,通常在通過唯一索引(如主鍵ID)進(jìn)行等值查詢并加鎖時(shí)觸發(fā)

  • Gap Lock(間隙鎖):鎖一個(gè)區(qū)間,不鎖定記錄本身,而是鎖定索引記錄之間的間隙,通常在可重復(fù)讀隔離級別下,通過范圍查詢或非唯一索引查詢時(shí)觸發(fā);防止幻讀.他確保在你的事務(wù)執(zhí)行期間,其他事務(wù)不能在這個(gè)間隙中"插入"新數(shù)據(jù)

  • Next - Key Lock : Record Lock + Gap Lock,鎖記錄和他前面的間隙

可重復(fù)讀隔離級別下默認(rèn)用Next-Key Lock,就是為了防幻讀

鎖類型鎖定對象包含記錄本身?主要目的
Record Lock單個(gè)索引記錄防止修改/刪除
Gap Lock索引之間的間隙防止插入(解決幻讀)
Next-Key Lock記錄 + 記錄前的間隙結(jié)合兩者優(yōu)點(diǎn),默認(rèn)鎖定方式

面試官追問

MVCC能解決幻讀嗎?

回答:能解決快照讀的幻讀,解決不了當(dāng)前讀的幻讀??煺兆x就是普通的select,走M(jìn)VCC版本鏈,事務(wù)開始時(shí)的ReadView定死了能看到哪些數(shù)據(jù),后面別人插入的新行看不見。但當(dāng)前讀比如 select...for update,讀的是最新數(shù)據(jù),這時(shí)候要靠間隙鎖來防幻讀,鎖住查詢范圍內(nèi)的間隙不讓別人插入。

1. 快照讀(Snapshot Read)

什么是快照讀? 就是最普通的 SELECT * FROM table WHERE ...。它不加任何鎖,讀取的是ReadView里的歷史版本,極大地提高了查詢性能.

  • 它是怎么防幻讀的? InnoDB 使用了 MVCC(多版本并發(fā)控制)。當(dāng)你開啟事務(wù)后的第一次查詢,系統(tǒng)會(huì)給你生成一個(gè)“快照”(ReadView)。就像給數(shù)據(jù)庫拍了張照片,無論之后別人怎么插入新數(shù)據(jù),你在這個(gè)事務(wù)里看到的永遠(yuǎn)是照片里的樣子。

  • 結(jié)論:在快照讀下,MVCC 完美解決了幻讀。你查一百次,結(jié)果都一樣。

2. 當(dāng)前讀(Current Read)

什么是當(dāng)前讀? 當(dāng)你需要讀取“最新版本”的數(shù)據(jù),或者準(zhǔn)備更新數(shù)據(jù)時(shí),就是當(dāng)前讀。常見的語句有:

  • SELECT ... FOR UPDATE (寫鎖)

  • SELECT ... LOCK IN SHARE MODE (讀鎖)

  • INSERT / UPDATE / DELETE (這些操作在執(zhí)行前都要先找準(zhǔn)那一行的最新位置)

  • 它為什么會(huì)有幻讀風(fēng)險(xiǎn)? 當(dāng)前讀不看“照片”,它要看“真人”。如果你只鎖住了已有的 5 行記錄,而沒管記錄之間的“空隙”,別人就能在空隙里插進(jìn)第 6 行。當(dāng)你再次執(zhí)行當(dāng)前讀時(shí),就會(huì)發(fā)現(xiàn)多出了一行。

  • 它是怎么解決的?Gap Lock(間隙鎖)。它不僅鎖住已有的行,還把行與行之間的“坑”也占了,不準(zhǔn)別人蹲坑(插入)。

  • 結(jié)論:在當(dāng)前讀下,MVCC 幫不上忙,必須靠間隙鎖來解決幻讀。

3. 最容易搞混的“幻讀”場景(面試高頻)

雖然上面說 MVCC 解決了快照讀的幻讀,但有一種特殊操作會(huì)讓 MVCC “破功”,讓你看到幻象:

場景演示:

  1. 事務(wù) A:先用“快照讀”查 id=5 的記錄,結(jié)果是不存在的。

  2. 事務(wù) B:插了一條 id=5 的記錄并提交

  3. 事務(wù) A:如果此時(shí)再 SELECT,依然查不到(快照保護(hù))。但是,如果事務(wù) A 此時(shí)執(zhí)行 UPDATE table SET name='new' WHERE id=5,這個(gè) UPDATE 是“當(dāng)前讀”,它能看到事務(wù) B 提交的那行。

  4. 結(jié)果UPDATE 成功了,事務(wù) A 發(fā)現(xiàn)自己居然更新了一條“不存在”的記錄!此時(shí)再 SELECT,id=5 的記錄就變出來了。

這就是所謂的“快照讀下的幻讀”: 因?yàn)槟愕氖聞?wù)里發(fā)生了一次“寫操作”(當(dāng)前讀),強(qiáng)行更新了版本號,導(dǎo)致那條新紀(jì)錄在你的 ReadView 里變現(xiàn)了。

  • 普通的SELECT是快照讀(不帶 for UPDATE 或 LOCK IN SHARE MODE)

  • 所有的修改操作都是當(dāng)前讀

undo log 什么時(shí)候會(huì)被清理?

回答:undolog不是事務(wù)提交就能刪的,要等沒有事務(wù)需要用到這些舊版本了才能清理。purge線程會(huì)掃描系統(tǒng)里活躍的事務(wù),找到最老的ReadView,比它還老的undolog才能刪除。所以長事務(wù)會(huì)導(dǎo)致undo log堆積,這也是為什么要避免長事務(wù)。

為什么redo log 要用循環(huán)寫而不是一直追加?

回答:redolog的作用是崩潰恢復(fù),checkpoint之前的日志對應(yīng)的數(shù)據(jù)頁已經(jīng)刷盤了,這部分日志就沒用了,可以覆蓋掉復(fù)用空間。一直追加的話磁盤會(huì)被撐爆。而且redolog大小固定有個(gè)好處,連續(xù)的磁盤空間順序?qū)懶阅芨?。binlog是一直追加的,因?yàn)樗糜谥鲝膹?fù)制和數(shù)據(jù)恢復(fù),歷史記錄不能丟。

總結(jié) 

到此這篇關(guān)于Mysql是如何實(shí)現(xiàn)事務(wù)的以及相關(guān)擴(kuò)展知識總結(jié)的文章就介紹到這了,更多相關(guān)Mysql實(shí)現(xiàn)事務(wù)及擴(kuò)展知識內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MySQL的索引和復(fù)合索引的實(shí)現(xiàn)

    MySQL的索引和復(fù)合索引的實(shí)現(xiàn)

    在數(shù)據(jù)庫中,索引是一種特殊的數(shù)據(jù)結(jié)構(gòu),它可以幫助我們快速地查詢和檢索數(shù)據(jù),本文主要介紹了MySQL的索引和復(fù)合索引的實(shí)現(xiàn),感興趣的可以了解一下
    2023-11-11
  • 一文詳解MySQL數(shù)據(jù)表設(shè)計(jì)的五大黃金原則

    一文詳解MySQL數(shù)據(jù)表設(shè)計(jì)的五大黃金原則

    這篇文章主要為大家詳細(xì)介紹了MySQL數(shù)據(jù)庫設(shè)計(jì)數(shù)據(jù)表的五大黃金原則,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解下
    2026-01-01
  • Mysql存儲過程如何實(shí)現(xiàn)歷史數(shù)據(jù)遷移

    Mysql存儲過程如何實(shí)現(xiàn)歷史數(shù)據(jù)遷移

    這篇文章主要介紹了Mysql存儲過程如何實(shí)現(xiàn)歷史數(shù)據(jù)遷移,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • MySQL不可忽視的數(shù)據(jù)庫約束(維護(hù)數(shù)據(jù)秩序)

    MySQL不可忽視的數(shù)據(jù)庫約束(維護(hù)數(shù)據(jù)秩序)

    數(shù)據(jù)庫約束是數(shù)據(jù)庫管理中不可或缺的一部分,它們在維護(hù)數(shù)據(jù)秩序、保證數(shù)據(jù)完整性和一致性方面發(fā)揮著重要作用,本文給大家介紹MySQL不可忽視的數(shù)據(jù)庫約束,感興趣的朋友一起看看吧
    2025-05-05
  • mysql數(shù)據(jù)存儲過程參數(shù)實(shí)例詳解

    mysql數(shù)據(jù)存儲過程參數(shù)實(shí)例詳解

    這篇文章主要介紹了mysql數(shù)據(jù)存儲過程參數(shù)實(shí)例詳解,小編覺得挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。
    2017-10-10
  • 如何捕獲和記錄SQL Server中發(fā)生的死鎖

    如何捕獲和記錄SQL Server中發(fā)生的死鎖

    本篇文章是對如何捕獲和記錄SQL Server中發(fā)生的死鎖進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • 淺談MySQL?中?null?值的那些坑

    淺談MySQL?中?null?值的那些坑

    本文解析MySQL中null值的定義與常見問題,如比較運(yùn)算符失效、WHERE條件誤用、IN子查詢異常,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-09-09
  • mysql如何設(shè)置主從數(shù)據(jù)庫的同步

    mysql如何設(shè)置主從數(shù)據(jù)庫的同步

    這篇文章主要介紹了mysql如何設(shè)置主從數(shù)據(jù)庫的同步問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • MySQL清空數(shù)據(jù)表的方法實(shí)例與分析

    MySQL清空數(shù)據(jù)表的方法實(shí)例與分析

    這篇文章給大家詳細(xì)介紹了MySQL清空數(shù)據(jù)表的方法,文中給出了實(shí)例代碼,對大家學(xué)習(xí)使用MySQL具有一定的參考借鑒價(jià)值,有需要的可以參考借鑒,下面來一起看看吧。
    2016-10-10
  • Mysql中的sql優(yōu)化實(shí)踐詳解

    Mysql中的sql優(yōu)化實(shí)踐詳解

    這篇文章主要介紹了Mysql中的sql優(yōu)化實(shí)踐詳解,SQL優(yōu)化是指通過改進(jìn)SQL語句的編寫和查詢計(jì)劃的設(shè)計(jì)來提高數(shù)據(jù)庫查詢性能的過程,在優(yōu)化SQL時(shí),可以采取一些措施來提升查詢性能,需要的朋友可以參考下
    2023-09-09

最新評論

华亭县| 磐安县| 白山市| 滕州市| 济源市| 旺苍县| 阿克苏市| 松滋市| 措美县| 溧水县| 藁城市| 什邡市| 西宁市| 曲水县| 墨竹工卡县| 桂平市| 祥云县| 白玉县| 连南| 伊吾县| 阿荣旗| 壶关县| 双城市| 武山县| 通渭县| 德令哈市| 甘德县| 梁山县| 德惠市| 革吉县| 津市市| 五原县| 石渠县| 崇礼县| 荣成市| 洛扎县| 大丰市| 佛山市| 山东| 东乡县| 莫力|