0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

系統(tǒng)是如何和MySQL交互的?

數(shù)據(jù)分析與開發(fā) ? 來源:CSDN ? 作者:專業(yè)IT技術(shù)社區(qū) ? 2021-03-10 15:44 ? 次閱讀

天天和數(shù)據(jù)庫打交道,一天能寫上幾十條 SQL 語句,但你知道我們的系統(tǒng)是如何和數(shù)據(jù)庫交互的嗎?MySQL 如何幫我們存儲(chǔ)數(shù)據(jù)、又是如何幫我們管理事務(wù)?....是不是感覺真的除了寫幾個(gè) 「select * from dual」外基本腦子一片空白?這篇文章就將帶你走進(jìn) MySQL 的世界,讓你徹底了解系統(tǒng)到底是如何和 MySQL 交互的,MySQL 在接受到我們發(fā)送的 SQL 語句時(shí)又分別做了哪些事情。

MySQL 驅(qū)動(dòng)

我們的系統(tǒng)在和 MySQL 數(shù)據(jù)庫進(jìn)行通信的時(shí)候,總不可能是平白無故的就能接收和發(fā)送請求,就算是你沒有做什么操作,那總該是有其他的“人”幫我們做了一些事情,基本上使用過 MySQL 數(shù)據(jù)庫的程序員多多少少都會(huì)知道 MySQL 驅(qū)動(dòng)這個(gè)概念的。就是這個(gè) MySQL 驅(qū)動(dòng)在底層幫我們做了對(duì)數(shù)據(jù)庫的連接,只有建立了連接了,才能夠有后面的交互。看下圖表示

89f1565e-7efa-11eb-8b86-12bb97331649.jpg

這樣的話,在系統(tǒng)和 MySQL 進(jìn)行交互之前,MySQL 驅(qū)動(dòng)會(huì)幫我們建立好連接,然后我們只需要發(fā)送 SQL 語句就可以執(zhí)行 CRUD 了。一次 SQL 請求就會(huì)建立一個(gè)連接,多個(gè)請求就會(huì)建立多個(gè)連接,那么問題來了,我們系統(tǒng)肯定不是一個(gè)人在使用的,換句話說肯定是存在多個(gè)請求同時(shí)去爭搶連接的情況。我們的 web 系統(tǒng)一般都是部署在 tomcat 容器中的,而 tomcat 是可以并發(fā)處理多個(gè)請求的,這就會(huì)導(dǎo)致多個(gè)請求會(huì)去建立多個(gè)連接,然后使用完再都去關(guān)閉,這樣會(huì)有什么問題呢?如下圖

8a0c7ce0-7efa-11eb-8b86-12bb97331649.jpg

java 系統(tǒng)在通過 MySQL 驅(qū)動(dòng)和 MySQL 數(shù)據(jù)庫連接的時(shí)候是基于 TCP/IP 協(xié)議的,所以如果每個(gè)請求都是新建連接和銷毀連接,那這樣勢必會(huì)造成不必要的浪費(fèi)和性能的下降,也就說上面的多線程請求的時(shí)候頻繁的創(chuàng)建和銷毀連接顯然是不合理的。必然會(huì)大大降低我們系統(tǒng)的性能,但是如果給你提供一些固定的用來連接的線程,這樣是不是不需要反復(fù)的創(chuàng)建和銷毀連接了呢?相信懂行的朋友會(huì)會(huì)心一笑,沒錯(cuò),說的就是數(shù)據(jù)庫連接池。

數(shù)據(jù)庫連接池:維護(hù)一定的連接數(shù),方便系統(tǒng)獲取連接,使用就去池子中獲取,用完放回去就可以了,我們不需要關(guān)心連接的創(chuàng)建與銷毀,也不需要關(guān)心線程池是怎么去維護(hù)這些連接的。

8a4ed7ac-7efa-11eb-8b86-12bb97331649.jpg

常見的數(shù)據(jù)庫連接池有 Druid、C3P0、DBCP,連接池實(shí)現(xiàn)原理在這里就不深入討論了,采用連接池大大節(jié)省了不斷創(chuàng)建與銷毀線程的開銷,這就是有名的「池化」思想,不管是線程池還是 HTTP 連接池,都能看到它的身影。

數(shù)據(jù)庫連接池

到這里,我們已經(jīng)知道的是我們的系統(tǒng)在訪問 MySQL 數(shù)據(jù)庫的時(shí)候,建立的連接并不是每次請求都會(huì)去創(chuàng)建的,而是從數(shù)據(jù)庫連接池中去獲取,這樣就解決了因?yàn)榉磸?fù)的創(chuàng)建和銷毀連接而帶來的性能損耗問題了。不過這里有個(gè)小問題,業(yè)務(wù)系統(tǒng)是并發(fā)的,而 MySQL 接受請求的線程呢,只有一個(gè)?

其實(shí) MySQL 的架構(gòu)體系中也已經(jīng)提供了這樣的一個(gè)池子,也是數(shù)據(jù)庫連池。雙方都是通過數(shù)據(jù)庫連接池來管理各個(gè)連接的,這樣一方面線程之前不需要是爭搶連接,更重要的是不需要反復(fù)的創(chuàng)建的銷毀連接。

8a75738a-7efa-11eb-8b86-12bb97331649.jpg

至此系統(tǒng)和 MySQL 數(shù)據(jù)庫之間的連接問題已經(jīng)說明清楚了。那么 MySQL 數(shù)據(jù)庫中的這些連接是怎么來處理的,又是誰來處理呢?

網(wǎng)絡(luò)連接必須由線程來處理

對(duì)計(jì)算基礎(chǔ)稍微有一點(diǎn)了解的的同學(xué)都是知道的,網(wǎng)絡(luò)中的連接都是由線程來處理的,所謂網(wǎng)絡(luò)連接說白了就是一次請求,每次請求都會(huì)有相應(yīng)的線程去處理的。也就是說對(duì)于 SQL 語句的請求在 MySQL 中是由一個(gè)個(gè)的線程去處理的。

8aa95ae2-7efa-11eb-8b86-12bb97331649.jpg

那這些線程會(huì)怎么去處理這些請求?會(huì)做哪些事情?

SQL 接口

MySQL 中處理請求的線程在獲取到請求以后獲取 SQL 語句去交給 SQL 接口去處理。

查詢解析器

假如現(xiàn)在有這樣的一個(gè) SQL

SELECT stuName,age,sex FROM students WHERE id=1

但是這個(gè) SQL 是寫給我們?nèi)丝吹?,機(jī)器哪里知道你在說什么?這個(gè)時(shí)候解析器就上場了。他會(huì)將 SQL 接口傳遞過來的 SQL 語句進(jìn)行解析,翻譯成 MySQL 自己能認(rèn)識(shí)的語言,至于怎么解析的就不需要再深究了,無非是自己一套相關(guān)的規(guī)則。

8ae0d792-7efa-11eb-8b86-12bb97331649.jpg

現(xiàn)在 SQL 已經(jīng)被解析成 MySQL 認(rèn)識(shí)的樣子的,那下一步是不是就是執(zhí)行嗎?理論上是這樣子的,但是 MySQL 的強(qiáng)大遠(yuǎn)不止于此,他還會(huì)幫我們選擇最優(yōu)的查詢路徑。

什么叫最優(yōu)查詢路徑?就是 MySQL 會(huì)按照自己認(rèn)為的效率最高的方式去執(zhí)行查詢

具體是怎么做到的呢?這就要說到 MySQL 的查詢優(yōu)化器了

MySQL 查詢優(yōu)化器

查詢優(yōu)化器內(nèi)部具體怎么實(shí)現(xiàn)的我們不需要是關(guān)心,我需要知道的是 MySQL 會(huì)幫我去使用他自己認(rèn)為的最好的方式去優(yōu)化這條 SQL 語句,并生成一條條的執(zhí)行計(jì)劃,比如你創(chuàng)建了多個(gè)索引,MySQL 會(huì)依據(jù)成本最小原則來選擇使用對(duì)應(yīng)的索引,這里的成本主要包括兩個(gè)方面, IO 成本和 CPU 成本

IO 成本: 即從磁盤把數(shù)據(jù)加載到內(nèi)存的成本,默認(rèn)情況下,讀取數(shù)據(jù)頁的 IO 成本是 1,MySQL 是以頁的形式讀取數(shù)據(jù)的,即當(dāng)用到某個(gè)數(shù)據(jù)時(shí),并不會(huì)只讀取這個(gè)數(shù)據(jù),而會(huì)把這個(gè)數(shù)據(jù)相鄰的數(shù)據(jù)也一起讀到內(nèi)存中,這就是有名的程序局部性原理,所以 MySQL 每次會(huì)讀取一整頁,一頁的成本就是 1。所以 IO 的成本主要和頁的大小有關(guān)

CPU 成本:將數(shù)據(jù)讀入內(nèi)存后,還要檢測數(shù)據(jù)是否滿足條件和排序等 CPU 操作的成本,顯然它與行數(shù)有關(guān),默認(rèn)情況下,檢測記錄的成本是 0.2。

MySQL 優(yōu)化器 會(huì)計(jì)算 「IO 成本 + CPU」 成本最小的那個(gè)索引來執(zhí)行

8b14cdc2-7efa-11eb-8b86-12bb97331649.jpg

優(yōu)化器執(zhí)行選出最優(yōu)索引等步驟后,會(huì)去調(diào)用存儲(chǔ)引擎接口,開始去執(zhí)行被 MySQL 解析過和優(yōu)化過的 SQL 語句

存儲(chǔ)引擎

查詢優(yōu)化器會(huì)調(diào)用存儲(chǔ)引擎的接口,去執(zhí)行 SQL,也就是說真正執(zhí)行 SQL 的動(dòng)作是在存儲(chǔ)引擎中完成的。數(shù)據(jù)是被存放在內(nèi)存或者是磁盤中的(存儲(chǔ)引擎是一個(gè)非常重要的組件,后面會(huì)詳細(xì)介紹)

執(zhí)行器

執(zhí)行器是一個(gè)非常重要的組件,因?yàn)榍懊婺切┙M件的操作最終必須通過執(zhí)行器去調(diào)用存儲(chǔ)引擎接口才能被執(zhí)行。執(zhí)行器最終最根據(jù)一系列的執(zhí)行計(jì)劃去調(diào)用存儲(chǔ)引擎的接口去完成 SQL 的執(zhí)行

8b50ef00-7efa-11eb-8b86-12bb97331649.jpg

初識(shí)存儲(chǔ)引擎

我們以一個(gè)更新的SQL語句來說明,SQL 如下

UPDATE students SET stuName = '小強(qiáng)' WHERE id = 1

當(dāng)我們系統(tǒng)發(fā)出這樣的查詢?nèi)ソ唤o MySQL 的時(shí)候,MySQL 會(huì)按照我們上面介紹的一系列的流程最終通過執(zhí)行器調(diào)用存儲(chǔ)引擎去執(zhí)行,流程圖就是上面那個(gè)。在執(zhí)行這個(gè) SQL 的時(shí)候 SQL 語句對(duì)應(yīng)的數(shù)據(jù)要么是在內(nèi)存中,要么是在磁盤中,如果直接在磁盤中操作,那這樣的隨機(jī)IO讀寫的速度肯定讓人無法接受的,所以每次在執(zhí)行 SQL 的時(shí)候都會(huì)將其數(shù)據(jù)加載到內(nèi)存中,這塊內(nèi)存就是 InnoDB 中一個(gè)非常重要的組件:緩沖池Buffer Pool

Buffer Pool

Buffer Pool (緩沖池)是InnoDB存儲(chǔ)引擎中非常重要的內(nèi)存結(jié)構(gòu),顧名思義,緩沖池其實(shí)就是類似 Redis 一樣的作用,起到一個(gè)緩存的作用,因?yàn)槲覀兌贾繫ySQL的數(shù)據(jù)最終是存儲(chǔ)在磁盤中的,如果沒有這個(gè) Buffer Pool 那么我們每次的數(shù)據(jù)庫請求都會(huì)磁盤中查找,這樣必然會(huì)存在 IO 操作,這肯定是無法接受的。但是有了 Buffer Pool 就是我們第一次在查詢的時(shí)候會(huì)將查詢的結(jié)果存到 Buffer Pool 中,這樣后面再有請求的時(shí)候就會(huì)先從緩沖池中去查詢,如果沒有再去磁盤中查找,然后再放到 Buffer Pool 中,如下圖

8b6a06ca-7efa-11eb-8b86-12bb97331649.jpg

按照上面的那幅圖,這條 SQL 語句的執(zhí)行步驟大致是這樣子的

innodb 存儲(chǔ)引擎會(huì)在緩沖池中查找 id=1 的這條數(shù)據(jù)是否存在

發(fā)現(xiàn)不存在,那么就會(huì)去磁盤中加載,并將其存放在緩沖池中

該條記錄會(huì)被加上一個(gè)獨(dú)占鎖(總不能你在修改的時(shí)候別人也在修改吧,這個(gè)機(jī)制本篇文章不重點(diǎn)介紹,以后會(huì)專門寫文章來詳細(xì)講解)

undo 日志文件:記錄數(shù)據(jù)被修改前的樣子

undo 顧名思義,就是沒有做,沒發(fā)生的意思。undo log 就是沒有發(fā)生事情(原本事情是什么)的一些日志

我們剛剛已經(jīng)說了,在準(zhǔn)備更新一條語句的時(shí)候,該條語句已經(jīng)被加載到 Buffer pool 中了,實(shí)際上這里還有這樣的操作,就是在將該條語句加載到 Buffer Pool 中的時(shí)候同時(shí)會(huì)往 undo 日志文件中插入一條日志,也就是將 id=1 的這條記錄的原來的值記錄下來。

這樣做的目的是什么?

Innodb 存儲(chǔ)引擎的最大特點(diǎn)就是支持事務(wù),如果本次更新失敗,也就是事務(wù)提交失敗,那么該事務(wù)中的所有的操作都必須回滾到執(zhí)行前的樣子,也就是說當(dāng)事務(wù)失敗的時(shí)候,也不會(huì)對(duì)原始數(shù)據(jù)有影響,看圖說話

8b9ff1fe-7efa-11eb-8b86-12bb97331649.jpg

這里說句額外話,其實(shí) MySQL 也是一個(gè)系統(tǒng),就好比我們平時(shí)開發(fā)的 java 的功能系統(tǒng)一樣,MySQL 使用的是自己相應(yīng)的語言開發(fā)出來的一套系統(tǒng)而已,它根據(jù)自己需要的功能去設(shè)計(jì)對(duì)應(yīng)的功能,它即然能做到哪些事情,那么必然是設(shè)計(jì)者們當(dāng)初這么定義或者是根據(jù)實(shí)際的場景變更演化而來的。所以大家放平心態(tài),把 MySQL 當(dāng)作一個(gè)系統(tǒng)去了解熟悉他。

到這一步,我們的執(zhí)行的 SQL 語句已經(jīng)被加載到 Buffer Pool 中了,然后開始更新這條語句,更新的操作實(shí)際是在Buffer Pool中執(zhí)行的,那問題來了,按照我們平時(shí)開發(fā)的一套理論緩沖池中的數(shù)據(jù)和數(shù)據(jù)庫中的數(shù)據(jù)不一致時(shí)候,我們就認(rèn)為緩存中的數(shù)據(jù)是臟數(shù)據(jù),那此時(shí) Buffer Pool 中的數(shù)據(jù)豈不是成了臟數(shù)據(jù)?沒錯(cuò),目前這條數(shù)據(jù)就是臟數(shù)據(jù),Buffer Pool 中的記錄是小強(qiáng) 數(shù)據(jù)庫中的記錄是旺財(cái) ,這種情況 MySQL是怎么處理的呢,繼續(xù)往下看

redo 日志文件:記錄數(shù)據(jù)被修改后的樣子

除了從磁盤中加載文件和將操作前的記錄保存到 undo 日志文件中,其他的操作是在內(nèi)存中完成的,內(nèi)存中的數(shù)據(jù)的特點(diǎn)就是:斷電丟失。如果此時(shí) MySQL 所在的服務(wù)器宕機(jī)了,那么 Buffer Pool 中的數(shù)據(jù)會(huì)全部丟失的。這個(gè)時(shí)候 redo 日志文件就需要來大顯神通了

畫外音:redo 日志文件是 InnoDB 特有的,他是存儲(chǔ)引擎級(jí)別的,不是 MySQL 級(jí)別的

redo 記錄的是數(shù)據(jù)修改之后的值,不管事務(wù)是否提交都會(huì)記錄下來,例如,此時(shí)將要做的是update students set stuName='小強(qiáng)' where id=1; 那么這條操作就會(huì)被記錄到 redo log buffer 中,啥?怎么又出來一個(gè) redo log buffer ,很簡單,MySQL 為了提高效率,所以將這些操作都先放在內(nèi)存中去完成,然后會(huì)在某個(gè)時(shí)機(jī)將其持久化到磁盤中。

8bd0734c-7efa-11eb-8b86-12bb97331649.jpg

截至目前,我們應(yīng)該都熟悉了 MySQL 的執(zhí)行器調(diào)用存儲(chǔ)引擎是怎么將一條 SQL 加載到緩沖池和記錄哪些日志的,流程如下:

準(zhǔn)備更新一條 SQL 語句

MySQL(innodb)會(huì)先去緩沖池(BufferPool)中去查找這條數(shù)據(jù),沒找到就會(huì)去磁盤中查找,如果查找到就會(huì)將這條數(shù)據(jù)加載到緩沖池(BufferPool)中

在加載到 Buffer Pool 的同時(shí),會(huì)將這條數(shù)據(jù)的原始記錄保存到 undo 日志文件中

innodb 會(huì)在 Buffer Pool 中執(zhí)行更新操作

更新后的數(shù)據(jù)會(huì)記錄在 redo log buffer 中

上面說的步驟都是在正常情況下的操作,但是程序的設(shè)計(jì)和優(yōu)化并不僅是為了這些正常情況而去做的,也是為了那些臨界區(qū)和極端情況下出現(xiàn)的問題去優(yōu)化設(shè)計(jì)的

這個(gè)時(shí)候如果服務(wù)器宕機(jī)了,那么緩存中的數(shù)據(jù)還是丟失了。真煩,竟然數(shù)據(jù)總是丟失,那能不能不要放在內(nèi)存中,直接保存到磁盤呢?很顯然不行,因?yàn)樵谏厦嬉惨呀?jīng)介紹了,在內(nèi)存中的操作目的是為了提高效率。

此時(shí),如果 MySQL 真的宕機(jī)了,那么沒關(guān)系的,因?yàn)?MySQL 會(huì)認(rèn)為本次事務(wù)是失敗的,所以數(shù)據(jù)依舊是更新前的樣子,并不會(huì)有任何的影響。

好了,語句也更新好了那么需要將更新的值提交啊,也就是需要提交本次的事務(wù)了,因?yàn)橹灰聞?wù)成功提交了,才會(huì)將最后的變更保存到數(shù)據(jù)庫,在提交事務(wù)前仍然會(huì)具有相關(guān)的其他操作

將 redo Log Buffer 中的數(shù)據(jù)持久化到磁盤中,就是將 redo log buffer 中的數(shù)據(jù)寫入到 redo log 磁盤文件中,一般情況下,redo log Buffer 數(shù)據(jù)寫入磁盤的策略是立即刷入磁盤(具體策略情況在下面小總結(jié)出會(huì)詳細(xì)介紹),上圖

8bf811f4-7efa-11eb-8b86-12bb97331649.jpg

如果 redo log Buffer 刷入磁盤后,數(shù)據(jù)庫服務(wù)器宕機(jī)了,那我們更新的數(shù)據(jù)怎么辦?此時(shí)數(shù)據(jù)是在內(nèi)存中,數(shù)據(jù)豈不是丟失了?不,這次數(shù)據(jù)就不會(huì)丟失了,因?yàn)?redo log buffer 中的數(shù)據(jù)已經(jīng)被寫入到磁盤了,已經(jīng)被持久化了,就算數(shù)據(jù)庫宕機(jī)了,在下次重啟的時(shí)候 MySQL 也會(huì)將 redo 日志文件內(nèi)容恢復(fù)到 Buffer Pool 中(這邊我的理解是和 Redis 的持久化機(jī)制是差不多的,在 Redis 啟動(dòng)的時(shí)候會(huì)檢查 rdb 或者是 aof 或者是兩者都檢查,根據(jù)持久化的文件來將數(shù)據(jù)恢復(fù)到內(nèi)存中)

到此為止,從執(zhí)行器開始調(diào)用存儲(chǔ)引擎接口做了哪些事情呢?

1.準(zhǔn)備更新一條 SQL 語句

2.MySQL(innodb)會(huì)先去緩沖池(BufferPool)中去查找這條數(shù)據(jù),沒找到就會(huì)去磁盤中查找,如果查找到就會(huì)將這條數(shù)據(jù)加載

到緩沖池(BufferPool)中 3.在加載到 Buffer Pool 的同時(shí),會(huì)將這條數(shù)據(jù)的原始記錄保存到 undo 日志文件中

4.innodb 會(huì)在 Buffer Pool 中執(zhí)行更新操作

5.更新后的數(shù)據(jù)會(huì)記錄在 redo log buffer 中

---到此是前面已經(jīng)總結(jié)過的---

6.MySQL 提交事務(wù)的時(shí)候,會(huì)將 redo log buffer 中的數(shù)據(jù)寫入到 redo 日志文件中 刷磁盤可以通過 innodb_flush_log_at_trx_commit 參數(shù)來設(shè)置

值為 0 表示不刷入磁盤

值為 1 表示立即刷入磁盤

值為 2 表示先刷到 os cache

7.myslq 重啟的時(shí)候會(huì)將 redo 日志恢復(fù)到緩沖池中

截止到目前為止,MySQL 的執(zhí)行器調(diào)用存儲(chǔ)引擎的接口去執(zhí)行【執(zhí)行計(jì)劃】提供的 SQL 的時(shí)候 InnoDB 做了哪些事情也就基本差不多了,但是這還沒完。下面還需要介紹下 MySQL 級(jí)別的日志文件 bin log

bin log 日志文件:記錄整個(gè)操作過程

上面介紹到的redo log是 InnoDB 存儲(chǔ)引擎特有的日志文件,而bin log屬于是 MySQL 級(jí)別的日志。redo log記錄的東西是偏向于物理性質(zhì)的,如:“對(duì)什么數(shù)據(jù),做了什么修改”。bin log是偏向于邏輯性質(zhì)的,類似于:“對(duì) students 表中的 id 為 1 的記錄做了更新操作” 兩者的主要特點(diǎn)總結(jié)如下:

bin log文件是如何刷入磁盤的?

bin log 的刷盤是有相關(guān)的策略的,策略可以通過sync_bin log來修改,默認(rèn)為 0,表示先寫入 os cache,也就是說在提交事務(wù)的時(shí)候,數(shù)據(jù)不會(huì)直接到磁盤中,這樣如果宕機(jī)bin log數(shù)據(jù)仍然會(huì)丟失。所以建議將sync_bin log設(shè)置為 1 表示直接將數(shù)據(jù)寫入到磁盤文件中。

刷入 bin log 有以下幾種模式

1、 STATMENT

基于 SQL 語句的復(fù)制(statement-based replication, SBR),每一條會(huì)修改數(shù)據(jù)的 SQL 語句會(huì)記錄到 bin log 中

【優(yōu)點(diǎn)】:不需要記錄每一行的變化,減少了 bin log 日志量,節(jié)約了 IO , 從而提高了性能

【缺點(diǎn)】:在某些情況下會(huì)導(dǎo)致主從數(shù)據(jù)不一致,比如執(zhí)行sysdate()、slepp()等

2、ROW

基于行的復(fù)制(row-based replication, RBR),不記錄每條SQL語句的上下文信息,僅需記錄哪條數(shù)據(jù)被修改了

【優(yōu)點(diǎn)】:不會(huì)出現(xiàn)某些特定情況下的存儲(chǔ)過程、或 function、或 trigger 的調(diào)用和觸發(fā)無法被正確復(fù)制的問題

【缺點(diǎn)】:會(huì)產(chǎn)生大量的日志,尤其是 alter table 的時(shí)候會(huì)讓日志暴漲

3、MIXED

基于 STATMENT 和 ROW 兩種模式的混合復(fù)制( mixed-based replication, MBR ),一般的復(fù)制使用 STATEMENT 模式保存 bin log ,對(duì)于 STATEMENT 模式無法復(fù)制的操作使用 ROW 模式保存 bin log

那既然bin log也是日志文件,那它是在什么記錄數(shù)據(jù)的呢?

其實(shí) MySQL 在提交事務(wù)的時(shí)候,不僅僅會(huì)將 redo log buffer 中的數(shù)據(jù)寫入到redo log 文件中,同時(shí)也會(huì)將本次修改的數(shù)據(jù)記錄到 bin log文件中,同時(shí)會(huì)將本次修改的bin log文件名和修改的內(nèi)容在bin log中的位置記錄到redo log中,最后還會(huì)在redo log最后寫入 commit 標(biāo)記,這樣就表示本次事務(wù)被成功的提交了。

如果在數(shù)據(jù)被寫入到bin log文件的時(shí)候,剛寫完,數(shù)據(jù)庫宕機(jī)了,數(shù)據(jù)會(huì)丟失嗎?

首先可以確定的是,只要redo log最后沒有 commit 標(biāo)記,說明本次的事務(wù)一定是失敗的。但是數(shù)據(jù)是沒有丟失了,因?yàn)橐呀?jīng)被記錄到redo log的磁盤文件中了。在 MySQL 重啟的時(shí)候,就會(huì)將 redo log 中的數(shù)據(jù)恢復(fù)(加載)到Buffer Pool中。

好了,到目前為止,一個(gè)更新操作我們基本介紹得差不多,但是你有沒有感覺少了哪件事情還沒有做?是不是你也發(fā)現(xiàn)這個(gè)時(shí)候被更新記錄僅僅是在內(nèi)存中執(zhí)行的,哪怕是宕機(jī)又恢復(fù)了也僅僅是將更新后的記錄加載到Buffer Pool中,這個(gè)時(shí)候 MySQL 數(shù)據(jù)庫中的這條記錄依舊是舊值,也就是說內(nèi)存中的數(shù)據(jù)在我們看來依舊是臟數(shù)據(jù),那這個(gè)時(shí)候怎么辦呢?

其實(shí) MySQL 會(huì)有一個(gè)后臺(tái)線程,它會(huì)在某個(gè)時(shí)機(jī)將我們Buffer Pool中的臟數(shù)據(jù)刷到 MySQL 數(shù)據(jù)庫中,這樣就將內(nèi)存和數(shù)據(jù)庫的數(shù)據(jù)保持統(tǒng)一了。

本文總結(jié)

到此,關(guān)于Buffer Pool、Redo Log Buffer 和undo log、redo log、bin log 概念以及關(guān)系就基本差不多了。

我們再回顧下

Buffer Pool 是 MySQL 的一個(gè)非常重要的組件,因?yàn)獒槍?duì)數(shù)據(jù)庫的增刪改操作都是在 Buffer Pool 中完成的

Undo log 記錄的是數(shù)據(jù)操作前的樣子

redo log 記錄的是數(shù)據(jù)被操作后的樣子(redo log 是 Innodb 存儲(chǔ)引擎特有)

bin log 記錄的是整個(gè)操作記錄(這個(gè)對(duì)于主從復(fù)制具有非常重要的意義)

從準(zhǔn)備更新一條數(shù)據(jù)到事務(wù)的提交的流程描述

首先執(zhí)行器根據(jù) MySQL 的執(zhí)行計(jì)劃來查詢數(shù)據(jù),先是從緩存池中查詢數(shù)據(jù),如果沒有就會(huì)去數(shù)據(jù)庫中查詢,如果查詢到了就將其放到緩存池中

在數(shù)據(jù)被緩存到緩存池的同時(shí),會(huì)寫入 undo log 日志文件

更新的動(dòng)作是在 BufferPool 中完成的,同時(shí)會(huì)將更新后的數(shù)據(jù)添加到 redo log buffer 中

完成以后就可以提交事務(wù),在提交的同時(shí)會(huì)做以下三件事

(第一件事)將redo log buffer中的數(shù)據(jù)刷入到 redo log 文件中

(第二件事)將本次操作記錄寫入到 bin log文件中

(第三件事)將 bin log 文件名字和更新內(nèi)容在 bin log 中的位置記錄到redo log中,同時(shí)在 redo log 最后添加 commit 標(biāo)記

至此表示整個(gè)更新事務(wù)已經(jīng)完成

總結(jié)

文章到這里就結(jié)束了,系統(tǒng)是如何和 MySQL 數(shù)據(jù)庫打交道,提交一條更新的 SQL 語句到 MySQL,MySQL 執(zhí)行了哪些流程,做了哪些事情從宏觀上都已經(jīng)講解完成了。

原文標(biāo)題:字節(jié)三面:詳解一條 SQL 的執(zhí)行過程

文章出處:【微信公眾號(hào):數(shù)據(jù)分析與開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    6684

    瀏覽量

    123140
  • SQL
    SQL
    +關(guān)注

    關(guān)注

    1

    文章

    753

    瀏覽量

    44032

原文標(biāo)題:字節(jié)三面:詳解一條 SQL 的執(zhí)行過程

文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    華納云:如何修改MySQL的默認(rèn)端口

    MySQL是世界上最流行的開源關(guān)系型數(shù)據(jù)庫管理系統(tǒng)之一。在某些情況下,由于安全性、網(wǎng)絡(luò)策略或端口沖突的原因,數(shù)據(jù)庫管理員可能需要更改MySQL服務(wù)的默認(rèn)監(jiān)聽端口。本文將指導(dǎo)您如何在不同的操作
    的頭像 發(fā)表于 07-22 14:56 ?269次閱讀
    華納云:如何修改<b class='flag-5'>MySQL</b>的默認(rèn)端口

    MySQL的整體邏輯架構(gòu)

    支持多種存儲(chǔ)引擎是眾所周知的MySQL特性,也是MySQL架構(gòu)的關(guān)鍵優(yōu)勢之一。如果能夠理解MySQL Server與存儲(chǔ)引擎之間是怎樣通過API交互的,將大大有利于理解
    的頭像 發(fā)表于 04-30 11:14 ?414次閱讀
    <b class='flag-5'>MySQL</b>的整體邏輯架構(gòu)

    MySQL密碼忘記了怎么辦?MySQL密碼快速重置方法步驟命令示例!

    MySQL密碼忘記了怎么辦?MySQL密碼快速重置方法步驟命令示例! MySQL是一種常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),如果你忘記了MySQL的密
    的頭像 發(fā)表于 01-12 16:06 ?705次閱讀

    mysql密碼忘了怎么重置

    mysql密碼忘了怎么重置? MySQL是一種開源的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),密碼用于保護(hù)數(shù)據(jù)庫的安全性和保密性。如果你忘記了MySQL的密碼,可以通過以下幾種方法進(jìn)行重置。 方法一:使用
    的頭像 發(fā)表于 12-27 16:51 ?5989次閱讀

    eclipse怎么連接數(shù)據(jù)庫mysql

    ,可以從MySQL官方網(wǎng)站下載安裝程序。根據(jù)操作系統(tǒng)選擇合適的版本,并按照安裝向?qū)нM(jìn)行安裝。 下載MySQL JDBC驅(qū)動(dòng)程序:在連接MySQL之前,你需要下載并配置JDBC驅(qū)動(dòng)程序。
    的頭像 發(fā)表于 12-06 11:06 ?1172次閱讀

    mysql配置失敗怎么辦

    MySQL是一款廣泛使用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),但在配置過程中可能會(huì)出現(xiàn)各種問題,導(dǎo)致配置失敗。本文將詳細(xì)介紹MySQL配置失敗的常見原因和對(duì)應(yīng)的解決方案,以幫助讀者快速排查和解決問題。 一、檢查
    的頭像 發(fā)表于 12-06 11:03 ?3281次閱讀

    mysql數(shù)據(jù)庫基礎(chǔ)命令

    MySQL是一個(gè)流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),經(jīng)常用于存儲(chǔ)、管理和操作數(shù)據(jù)。在本文中,我們將詳細(xì)介紹MySQL的基礎(chǔ)命令,并提供與每個(gè)命令相關(guān)的詳細(xì)解釋。 登錄MySQL 要登錄
    的頭像 發(fā)表于 12-06 10:56 ?530次閱讀

    oracle和mysql語法區(qū)別大嗎

    Oracle和MySQL是兩種不同的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS)。雖然它們都是遵循SQL標(biāo)準(zhǔn),但在語法和特性上仍存在一些區(qū)別。以下是對(duì)Oracle和MySQL語法區(qū)別的詳細(xì)說明: 數(shù)據(jù)類型
    的頭像 發(fā)表于 12-06 10:26 ?1079次閱讀

    php的mysql無法啟動(dòng)

    MySQL是一種常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),而PHP是一種廣泛應(yīng)用于服務(wù)器端的腳本語言。在使用PHP開發(fā)網(wǎng)站或應(yīng)用時(shí),經(jīng)常會(huì)碰到MySQL無法啟動(dòng)的問題。本文將詳細(xì)介紹解決MySQL
    的頭像 發(fā)表于 12-04 15:59 ?1359次閱讀

    mysql和sql server區(qū)別

    MySQL和SQL Server是兩種常見的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS),用于存儲(chǔ)和管理數(shù)據(jù)庫。雖然它們都支持SQL語言,但在其他方面存在一些顯著的區(qū)別。以下是MySQL和SQL Server
    的頭像 發(fā)表于 11-21 11:07 ?1451次閱讀

    MySQL忘記root密碼解決方案

    MySQL 是一個(gè)流行的開源關(guān)系型數(shù)據(jù)庫管理系統(tǒng),被廣泛應(yīng)用于 web 應(yīng)用程序和服務(wù)器環(huán)境中。MySQL的root用戶是具有最高權(quán)限和特權(quán)的用戶,可以操作所有數(shù)據(jù)庫和表。如果忘記了root用戶
    的頭像 發(fā)表于 11-21 11:04 ?610次閱讀

    安裝sqlyog之前要裝mysql

    在安裝 SQLyog 前是否需要安裝 MySQL 取決于您的情況。MySQL 是一個(gè)關(guān)系型數(shù)據(jù)庫管理系統(tǒng),而 SQLyog 是一個(gè)可視化數(shù)據(jù)庫管理工具,主要用于管理和操作 MySQL
    的頭像 發(fā)表于 11-21 11:02 ?1156次閱讀

    MySQL導(dǎo)出的步驟

    MySQL是一種常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),用于存儲(chǔ)和管理大量的結(jié)構(gòu)化數(shù)據(jù)。在實(shí)際應(yīng)用中,我們經(jīng)常需要將MySQL數(shù)據(jù)庫中的數(shù)據(jù)導(dǎo)出到其他地方,如備份數(shù)據(jù)、數(shù)據(jù)遷移、數(shù)據(jù)分析等。下面是使用My
    的頭像 發(fā)表于 11-21 10:58 ?739次閱讀

    mysql基礎(chǔ)語句大全

    MySQL是一個(gè)開放源碼的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),使用SQL作為其查詢語言。它是Web開發(fā)中常用的數(shù)據(jù)庫管理系統(tǒng)之一。MySQL的語法十分豐富,可以執(zhí)行各種數(shù)據(jù)庫操作,包括創(chuàng)建、修改、刪
    的頭像 發(fā)表于 11-16 16:42 ?1856次閱讀

    mysql是一個(gè)什么類型的數(shù)據(jù)庫

    MySQL是一種關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS),用于存儲(chǔ)和管理大量結(jié)構(gòu)化數(shù)據(jù)。它被廣泛用于各種應(yīng)用程序和網(wǎng)站的后端,包括電子商務(wù)平臺(tái)、社交媒體網(wǎng)站、金融系統(tǒng)等等。MySQL的特點(diǎn)是
    的頭像 發(fā)表于 11-16 14:43 ?1646次閱讀