国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
粒度
行鎖的種類
行鎖的實(shí)現(xiàn)算法
Record Lock
Gap Lock
Next-Key Lock
鎖之于隔離性
MVCC
版本鏈
ReadView
開始查詢
RR 級別的幻讀
一條SQL更新語句怎么運(yùn)行
redo log
Buffer Pool
binlog
binlog 和 redo log
首頁 Java Java面試題 面試官:MySQL 是如何實(shí)現(xiàn) ACID 的?

面試官:MySQL 是如何實(shí)現(xiàn) ACID 的?

Aug 17, 2023 pm 02:39 PM
java java面試題

在面試中,面試官只要問MySQL的ACID,然后可以立馬背出來八股文來(還有部分人估計(jì)都還回答不上來)。更可惡的是,有些面試官不按套路出牌,會繼續(xù)問了,MySQL到底是如何實(shí)現(xiàn)ACID的呢?

蒙圈了吧,實(shí)話實(shí)說,這道題能勸退95%的人。

今天,本文主要探討MySQL InnoDB?引擎下ACID的實(shí)現(xiàn)原理,對于諸如什么是事務(wù),隔離級別的含義等基礎(chǔ)知識不做過多闡述。

ACID

MySQL 作為一個關(guān)系型數(shù)據(jù)庫,以最常見的 InnoDB 引擎來說,是如何保證 ACID 的。

  • (Atomicity原子性:?事務(wù)是最小的執(zhí)行單位,不允許分割。原子性確保動作要么全部完成,要么完全不起作用;
  • (Consistency)一致性:?執(zhí)行事務(wù)前后,數(shù)據(jù)保持一致;
  • (Isolation)隔離性:?并發(fā)訪問數(shù)據(jù)庫時(shí),一個事務(wù)不被其他事務(wù)所干擾。
  • (Durability)持久性:?一個事務(wù)被提交之后。對數(shù)據(jù)庫中數(shù)據(jù)的改變是持久的,即使數(shù)據(jù)庫發(fā)生故障。

隔離性

先說說隔離性,首先是四種隔離級別。

隔離級別 說明
讀未提交 一個事務(wù)還沒提交時(shí),它做的變更就能被別的事務(wù)看到
讀提交 一個事務(wù)提交之后,它做的變更才會被其他事務(wù)看到
可重復(fù)讀 一個事務(wù)中,對同一份數(shù)據(jù)的讀取結(jié)果總是相同的,無論是否有其他事務(wù)對這份數(shù)據(jù)進(jìn)行操作,以及這個事務(wù)是否提交。InnoDB默認(rèn)級別。
串行化 事務(wù)串行化執(zhí)行,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞,隔離級別最高,犧牲系統(tǒng)并發(fā)性。

不同的隔離級別是為了解決不同的問題。也就是臟讀、幻讀、不可重復(fù)讀。

隔離級別 臟讀 不可重復(fù)讀 幻讀
讀未提交 可以出現(xiàn) 可以出現(xiàn) 可以出現(xiàn)
讀提交 不允許出現(xiàn) 可以出現(xiàn) 可以出現(xiàn)
可重復(fù)讀 不允許出現(xiàn) 不允許出現(xiàn) 可以出現(xiàn)
序列化 不允許出現(xiàn) 不允許出現(xiàn) 不允許出現(xiàn)

那么不同的隔離級別,隔離性是如何實(shí)現(xiàn)的,為什么不同事物間能夠互不干擾?答案是?鎖 和 MVCC。

先來說說鎖, MySQL 有多少鎖。

粒度

從粒度上來說就是表鎖、頁鎖、行鎖。表鎖有意向共享鎖、意向排他鎖、自增鎖等。行鎖是在引擎層由各個引擎自己實(shí)現(xiàn)的。但并不是所有的引擎都支持行鎖,比如 MyISAM 引擎就不支持行鎖。

行鎖的種類

在 InnoDB 事務(wù)中,行鎖通過給索引上的索引項(xiàng)加鎖來實(shí)現(xiàn)。這意味著只有通過索引條件檢索數(shù)據(jù),InnoDB才使用行級鎖,否則將使用表鎖。行級鎖定同樣分為兩種類型:共享鎖和排他鎖,以及加鎖前需要先獲得的意向共享鎖和意向排他鎖。

  • 共享鎖:讀鎖,允許其他事務(wù)再加S鎖,不允許其他事務(wù)再加X鎖,即其他事務(wù)只讀不可寫。select...lock in share mode?加鎖。select...lock in share mode?加鎖。
  • 排它鎖:寫鎖,不允許其他事務(wù)再加S鎖或者X鎖。insert、update、delete、for update
排它鎖:寫鎖,不允許其他事務(wù)再加S鎖或者X鎖。insert、update、delete、for update加鎖。

行鎖是在需要的時(shí)候才加

上??的,但并不是不需要了就立刻釋放,而是要等到事務(wù)結(jié)束時(shí)才釋放。這個就是兩階段鎖協(xié)議。????

行鎖的實(shí)現(xiàn)算法

Record Lock

單個行記錄上的鎖,總是會去鎖住索引記錄。

Gap Lock

間隙鎖,想一下幻讀的原因,其實(shí)就是行鎖只能鎖住行,但新插入記錄這個動作,要更新的是記錄之間的“間隙”。所以加入間隙鎖來解決幻讀。

Next-Key Lock

Gap Lock + Record Lock, 左開又閉。

鎖之于隔離性

大致介紹了下鎖,可以看到。有了鎖,當(dāng)某事務(wù)正在寫數(shù)據(jù)時(shí),其他事務(wù)獲取不到寫鎖,就無法寫數(shù)據(jù),一定程度上保證了事務(wù)間的隔離。但前面說,加了寫鎖,為什么其他事務(wù)也能讀數(shù)據(jù)呢,不是獲取不到讀鎖嗎?

MVCC

前面說到,有了鎖,當(dāng)前事務(wù)沒有寫鎖就不能修改數(shù)據(jù),但還是能讀的,而且讀的時(shí)候,即使該行數(shù)據(jù)其他事務(wù)已修改且提交,還是可以重復(fù)讀到同樣的值。這就是MVCC,多版本的并發(fā)控制,Multi-Version Concurrency Control。

版本鏈

Innodb 中行記錄的存儲格式,有一些額外的字段:DATA_TRX_ID和DATA_ROLL_PTR。

  • DATA_TRX_ID:數(shù)據(jù)行版本號。用來標(biāo)識最近對本行記錄做修改的事務(wù) id。
  • DATA_ROLL_PTR:指向該行回滾段的指針。該行記錄上所有舊版本,在?undo log?中都通過鏈表的形式組織。

undo log : 記錄數(shù)據(jù)被修改之前的日志,后面會詳細(xì)說。

面試官:MySQL 是如何實(shí)現(xiàn) ACID 的?

ReadView

在每一條 SQL 開始的時(shí)候被創(chuàng)建,有幾個重要屬性:

  • trx_ids:?當(dāng)前系統(tǒng)活躍(未提交)事務(wù)版本號集合。
  • low_limit_id:?創(chuàng)建當(dāng)前 read view 時(shí)“當(dāng)前系統(tǒng)最大事務(wù)版本號+1”。
  • up_limit_id:?創(chuàng)建當(dāng)前read view 時(shí)“系統(tǒng)正處于活躍事務(wù)最小版本號”
  • creator_trx_id:?創(chuàng)建當(dāng)前read view的事務(wù)版本號;
面試官:MySQL 是如何實(shí)現(xiàn) ACID 的?

開始查詢

現(xiàn)在開始查詢,一個 select 過來了,找到了一行數(shù)據(jù)。

  • DATA_TRX_ID

  • DATA_TRX_ID >= low_limit_id:

    說明該數(shù)據(jù)是在當(dāng)前read view 創(chuàng)建后才產(chǎn)生的,數(shù)據(jù)不顯示。


    • 不顯示怎么辦,根據(jù)?DATA_ROLL_PTR 從 undo log 中找到歷史版本,找不到就空。
  • up_limit_id ?<low_limit_id :就要看隔離級別了。

面試官:MySQL 是如何實(shí)現(xiàn) ACID 的?

RR 級別的幻讀

有了鎖和 MVCC , 事務(wù)的隔離性得到解決。這里要引申一下,默認(rèn)的 RR 的級別,解決了幻讀嗎?幻讀通常針對的是?INSERT,?不可重復(fù)度則針對?UPDATE 。

事物 1 事物 2
begin begin
select * from dept
- 插入部門(名稱)值(“A”)
- 提交
更新部門集名稱=“B”
提交

我們期望是

id??name
1???A
2???B

實(shí)際卻是

id??name
1???B
2???B

其實(shí)在 MySQL 可重復(fù)讀的隔離級別中并不是完全解決了幻讀的問題,而是解決了讀數(shù)據(jù)情況下的幻讀問題。而對于修改的操作依舊存在幻讀問題,就是說 MVCC 對于幻讀的解決時(shí)不徹底的。

原子性

接著說說原子性。前文有提到 undo log ,回滾日志。隔離性的MVCC其實(shí)就是依靠它來實(shí)現(xiàn)的,原子性也是。實(shí)現(xiàn)原子性的關(guān)鍵,是當(dāng)事務(wù)回滾時(shí)能夠撤銷所有已經(jīng)成功執(zhí)行的sql語句。

當(dāng)事務(wù)對數(shù)據(jù)庫進(jìn)行修改時(shí),InnoDB會生成對應(yīng)的 undo log;如果事務(wù)執(zhí)行失敗或調(diào)用了 rollback,導(dǎo)致事務(wù)需要回滾,便可以利用 undo log 中的信息將數(shù)據(jù)回滾到修改之前的樣子。undo log 屬于邏輯日志,它記錄的是sql執(zhí)行相關(guān)的信息。當(dāng)發(fā)生回滾時(shí),InnoDB 會根據(jù) undo log 的內(nèi)容做與之前相反的工作:

  • 對于每個 insert,回滾時(shí)會執(zhí)行 delete;
  • 對于每個 delete,回滾時(shí)會執(zhí)行insert;
  • 對于每個 update,回滾時(shí)會執(zhí)行一個相反的 update,把數(shù)據(jù)改回去。

以update操作為例:當(dāng)事務(wù)執(zhí)行update時(shí),其生成的undo log中會包含被修改行的主鍵(以便知道修改了哪些行)、修改了哪些列、這些列在修改前后的值等信息,回滾時(shí)便可以使用這些信息將數(shù)據(jù)還原到update之前的狀態(tài)。

持久性

Innnodb有很多 log,持久性靠的是 redo log。

一條SQL更新語句怎么運(yùn)行

持久性肯定和寫有關(guān),MySQL 里經(jīng)常說到的 WAL 技術(shù),WAL 的全稱是 Write-Ahead Logging,它的關(guān)鍵點(diǎn)就是先寫日志,再寫磁盤。就像小店做生意,有個粉板,有個賬本,來客了先寫粉板,等不忙的時(shí)候再寫賬本。

redo log

redo log 就是這個粉板,當(dāng)有一條記錄要更新時(shí),InnoDB 引擎就會先把記錄寫到 redo log(并更新內(nèi)存),這個時(shí)候更新就算完成了。在適當(dāng)?shù)臅r(shí)候,將這個操作記錄更新到磁盤里面,而這個更新往往是在系統(tǒng)比較空閑的時(shí)候做,這就像打烊以后掌柜做的事。

redo log 有兩個特點(diǎn):

  • 大小固定,循環(huán)寫
  • crash-safe

對于redo log 是有兩階段的:commit 和 prepare 如果不使用“兩階段提交”,數(shù)據(jù)庫的狀態(tài)就有可能和用它的日志恢復(fù)出來的庫的狀態(tài)不一致. 好了,先到這里,看看另一個。

Buffer Pool

InnoDB還提供了緩存,Buffer Pool 中包含了磁盤中部分?jǐn)?shù)據(jù)頁的映射,作為訪問數(shù)據(jù)庫的緩沖:

  • 當(dāng)讀取數(shù)據(jù)時(shí),會先從Buffer Pool中讀取,如果Buffer Pool中沒有,則從磁盤讀取后放入Buffer Pool;
  • 當(dāng)向數(shù)據(jù)庫寫入數(shù)據(jù)時(shí),會首先寫入Buffer Pool,Buffer Pool中修改的數(shù)據(jù)會定期刷新到磁盤中。

Buffer Pool 的使用大大提高了讀寫數(shù)據(jù)的效率,但是也帶了新的問題:如果MySQL宕機(jī),而此時(shí) Buffer Pool 中修改的數(shù)據(jù)還沒有刷新到磁盤,就會導(dǎo)致數(shù)據(jù)的丟失,事務(wù)的持久性無法保證。

所以加入了 redo log。當(dāng)數(shù)據(jù)修改時(shí),除了修改Buffer Pool中的數(shù)據(jù),還會在redo log記錄這次操作;

當(dāng)事務(wù)提交時(shí),會調(diào)用fsync接口對redo log進(jìn)行刷盤。

如果MySQL宕機(jī),重啟時(shí)可以讀取redo log中的數(shù)據(jù),對數(shù)據(jù)庫進(jìn)行恢復(fù)。

redo log采用的是WAL(Write-ahead logging,預(yù)寫式日志),所有修改先寫入日志,再更新到Buffer Pool,保證了數(shù)據(jù)不會因MySQL宕機(jī)而丟失,從而滿足了持久性要求。而且這樣做還有兩個優(yōu)點(diǎn):

  • 刷臟頁是隨機(jī) IO,redo log 順序 IO
  • 刷臟頁以Page為單位,一個Page上的修改整頁都要寫;而redo log 只包含真正需要寫入的,無效 IO 減少。

binlog

說到這,可能會疑問還有個 bin log 也是寫操作并用于數(shù)據(jù)的恢復(fù),有啥區(qū)別呢。

  • 層次:redo log 是 innoDB 引擎特有的,server 層的叫 binlog(歸檔日志)
  • 內(nèi)容:redolog 是物理日志,記錄“在某個數(shù)據(jù)頁上做了什么修改”;binlog 是邏輯日志,是語句的原始邏輯,如“給 ID=2 這一行的 c 字段加 1 ”
  • 寫入:redolog 循環(huán)寫且寫入時(shí)機(jī)較多,binlog 追加且在事務(wù)提交時(shí)寫入
binlog 和 redo log

對于語句?update T set c=c+1 where ID=2;

  1. 執(zhí)行器先找引擎取 ID=2 這一行。ID 是主鍵,直接用樹搜索找到。如果 ID = 2 這一行所在數(shù)據(jù)頁就在內(nèi)存中,就直接返回給執(zhí)行器;否則,需要先從磁盤讀入內(nèi)存,再返回。
  2. 執(zhí)行器拿到引擎給的行數(shù)據(jù),把這個值加上 1,N+1,得到新的一行數(shù)據(jù),再調(diào)用引擎接口寫入這行新數(shù)據(jù)。
  3. 引擎將這行新數(shù)據(jù)更新到內(nèi)存中,同時(shí)將這個更新操作記錄到 redo log 里面,此時(shí) redo log 處于 prepare 狀態(tài)。然后告知執(zhí)行器執(zhí)行完成了,隨時(shí)可以提交事務(wù)。
  4. 執(zhí)行器生成這個操作的 binlog,并把 binlog 寫入磁盤。
  5. 執(zhí)行器調(diào)用引擎的提交事務(wù)接口,引擎把剛剛寫入的 redo log 改成提交(commit)狀態(tài),更新完成

為什么先寫 redo log 呢 ?

  • 先 redo 后 bin : binlog 丟失,少了一次更新,恢復(fù)后仍是0。
  • 先 bin 后 redo : 多了一次事務(wù),恢復(fù)后是1。

一致性

一致性是事務(wù)追求的最終目標(biāo),前問所訴的原子性、持久性和隔離性,其實(shí)都是為了保證數(shù)據(jù)庫狀態(tài)的一致性。當(dāng)然,上文都是數(shù)據(jù)庫層面的保障,一致性的實(shí)現(xiàn)也需要應(yīng)用層面進(jìn)行保障。

也就是你的業(yè)務(wù),比如購買操作只扣除用戶的余額,不減庫存,肯定無法保證狀態(tài)的一致。

總結(jié)

MySQL 都很熟, ACID 也知道是個啥,但 MySQL 的 ACID 怎么實(shí)現(xiàn)的?

有時(shí)候,就像你知道了有 undo log、redo log 但可能并不太清楚為什么有,當(dāng)知道了設(shè)計(jì)的目的,了解起來就會更加清晰了。

以上是面試官:MySQL 是如何實(shí)現(xiàn) ACID 的?的詳細(xì)內(nèi)容。更多信息請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級代碼編輯軟件(SublimeText3)

熱門話題

Laravel 教程
1601
29
PHP教程
1502
276
如何使用JDBC處理Java的交易? 如何使用JDBC處理Java的交易? Aug 02, 2025 pm 12:29 PM

要正確處理JDBC事務(wù),必須先關(guān)閉自動提交模式,再執(zhí)行多個操作,最后根據(jù)結(jié)果提交或回滾;1.調(diào)用conn.setAutoCommit(false)以開始事務(wù);2.執(zhí)行多個SQL操作,如INSERT和UPDATE;3.若所有操作成功則調(diào)用conn.commit(),若發(fā)生異常則調(diào)用conn.rollback()確保數(shù)據(jù)一致性;同時(shí)應(yīng)使用try-with-resources管理資源,妥善處理異常并關(guān)閉連接,避免連接泄漏;此外建議使用連接池、設(shè)置保存點(diǎn)實(shí)現(xiàn)部分回滾,并保持事務(wù)盡可能短以提升性能。

了解Java虛擬機(jī)(JVM)內(nèi)部 了解Java虛擬機(jī)(JVM)內(nèi)部 Aug 01, 2025 am 06:31 AM

TheJVMenablesJava’s"writeonce,runanywhere"capabilitybyexecutingbytecodethroughfourmaincomponents:1.TheClassLoaderSubsystemloads,links,andinitializes.classfilesusingbootstrap,extension,andapplicationclassloaders,ensuringsecureandlazyclassloa

如何使用Java的日歷? 如何使用Java的日歷? Aug 02, 2025 am 02:38 AM

使用java.time包中的類替代舊的Date和Calendar類;2.通過LocalDate、LocalDateTime和LocalTime獲取當(dāng)前日期時(shí)間;3.使用of()方法創(chuàng)建特定日期時(shí)間;4.利用plus/minus方法不可變地增減時(shí)間;5.使用ZonedDateTime和ZoneId處理時(shí)區(qū);6.通過DateTimeFormatter格式化和解析日期字符串;7.必要時(shí)通過Instant與舊日期類型兼容;現(xiàn)代Java中日期處理應(yīng)優(yōu)先使用java.timeAPI,它提供了清晰、不可變且線

比較Java框架:Spring Boot vs Quarkus vs Micronaut 比較Java框架:Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

前形式攝取,quarkusandmicronautleaddueTocile timeProcessingandGraalvSupport,withquarkusoftenpernperforminglightbetterine nosserless notelless centarios.2。

了解網(wǎng)絡(luò)端口和防火墻 了解網(wǎng)絡(luò)端口和防火墻 Aug 01, 2025 am 06:40 AM

NetworkPortSandFireWallsworkTogetHertoEnableCommunication whereSeringSecurity.1.NetWorkPortSareVirtualendPointSnumbered0-655 35,with-Well-with-Newonportslike80(HTTP),443(https),22(SSH)和25(smtp)sindiessingspefificservices.2.portsoperateervertcp(可靠,c

垃圾收集如何在Java工作? 垃圾收集如何在Java工作? Aug 02, 2025 pm 01:55 PM

Java的垃圾回收(GC)是自動管理內(nèi)存的機(jī)制,通過回收不可達(dá)對象釋放堆內(nèi)存,減少內(nèi)存泄漏風(fēng)險(xiǎn)。1.GC從根對象(如棧變量、活動線程、靜態(tài)字段等)出發(fā)判斷對象可達(dá)性,無法到達(dá)的對象被標(biāo)記為垃圾。2.基于標(biāo)記-清除算法,標(biāo)記所有可達(dá)對象,清除未標(biāo)記對象。3.采用分代收集策略:新生代(Eden、S0、S1)頻繁執(zhí)行MinorGC;老年代執(zhí)行較少但耗時(shí)較長的MajorGC;Metaspace存儲類元數(shù)據(jù)。4.JVM提供多種GC器:SerialGC適用于小型應(yīng)用;ParallelGC提升吞吐量;CMS降

比較Java構(gòu)建工具:Maven vs. Gradle 比較Java構(gòu)建工具:Maven vs. Gradle Aug 03, 2025 pm 01:36 PM

Gradleisthebetterchoiceformostnewprojectsduetoitssuperiorflexibility,performance,andmoderntoolingsupport.1.Gradle’sGroovy/KotlinDSLismoreconciseandexpressivethanMaven’sverboseXML.2.GradleoutperformsMaveninbuildspeedwithincrementalcompilation,buildcac

以身作則,解釋說明 以身作則,解釋說明 Aug 02, 2025 am 06:26 AM

defer用于在函數(shù)返回前執(zhí)行指定操作,如清理資源;參數(shù)在defer時(shí)立即求值,函數(shù)按后進(jìn)先出(LIFO)順序執(zhí)行;1.多個defer按聲明逆序執(zhí)行;2.常用于文件關(guān)閉等安全清理;3.可修改命名返回值;4.即使發(fā)生panic也會執(zhí)行,適合用于recover;5.避免在循環(huán)中濫用defer,防止資源泄漏;正確使用可提升代碼安全性和可讀性。

See all articles