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

詳解MySQL如何保證數(shù)據(jù)一致性

 更新時(shí)間:2024年01月04日 08:55:58   作者:王二蛋!  
對(duì)于一個(gè)數(shù)據(jù)庫(kù)而言,除了數(shù)據(jù)的持久性、不丟失之外,一致性也是非常重要的,不然這個(gè)數(shù)據(jù)是沒(méi)有任何意義的,在使用MySQL時(shí),數(shù)據(jù)不一致的情況也可能出現(xiàn),所以,本文就來(lái)看看MySQL是如何保證數(shù)據(jù)一致的,需要的朋友可以參考下

MySQL保證的一致性

在這之前先劃清一下界限,看一下MySQL保證的是哪里的一致性。

拿一個(gè)最簡(jiǎn)單的轉(zhuǎn)賬例子,用戶A向用戶B轉(zhuǎn)1000元,正常的sql是這樣的

update account set balance=balance-4000 where user='A' and balance >= 4000;
update account set balance=balance+4000 where user='B';

示例表數(shù)據(jù)如下

在這里插入圖片描述

如果最終用戶A賬戶沒(méi)有扣4000,而用戶B賬戶多了4000,總金額也無(wú)緣無(wú)故的多了4000。這個(gè)時(shí)候就造成了數(shù)據(jù)不一致了。出現(xiàn)這個(gè)問(wèn)題可能存在幾個(gè)原因:

  • 在MySQL客戶端執(zhí)行sql時(shí)沒(méi)有做校驗(yàn)。如果用戶A余額并不足以4000,由于沒(méi)有校驗(yàn),兩條sql都會(huì)成功執(zhí)行,用戶B就會(huì)憑空多出4000。
  • 兩條sql并不在同一事務(wù)中??赡躶ql1執(zhí)行失敗了,sql2執(zhí)行成功,由于不再一個(gè)事務(wù)中導(dǎo)致用戶B多了4000。
  • 在MySQL內(nèi)部執(zhí)行時(shí)因?yàn)槟承┕收隙霈F(xiàn)了不一致情況。

很顯然,第三點(diǎn)是需要MySQL解決處理的。而第一點(diǎn)是屬于MySQL客戶端的邏輯BUG,第二點(diǎn)會(huì)存在客戶端在使用事務(wù)時(shí)不遵循規(guī)則的情況,都屬于外部因素,MySQL不可控。

所以,MySQL保證的一致性是:在一個(gè)事務(wù)中的DML(增刪改)操作。盡管DML本身可能存在問(wèn)題。

MySQL發(fā)生不一致環(huán)節(jié)

劃清界限后再分析一下在DML執(zhí)行過(guò)程中,哪個(gè)環(huán)節(jié)會(huì)發(fā)生數(shù)據(jù)不一致。 以上面的sql為例,假設(shè)已經(jīng)進(jìn)行過(guò)校驗(yàn)且在同一事務(wù)。

并發(fā)沖突

在執(zhí)行第一條sql時(shí),「執(zhí)行器」會(huì)通過(guò)條件user='A' and balance >= 4000在「存儲(chǔ)引擎」獲取到符合條件的記錄,然后進(jìn)行balance扣減操作。(不知道這個(gè)流程的可以看下前面的文章)

如果這個(gè)時(shí)候存在并發(fā)現(xiàn)象,扣減操作可能會(huì)執(zhí)行多次,這個(gè)balance肯定就不是預(yù)想中的結(jié)果了,也就發(fā)生數(shù)據(jù)不一致了。如下圖

在這里插入圖片描述

當(dāng)3個(gè)update請(qǐng)求同一時(shí)間調(diào)用存儲(chǔ)引擎對(duì)同一數(shù)據(jù)頁(yè)更新后,正常情況下,balance值應(yīng)該為0。但是因?yàn)椴l(fā)操作,balance的值可能會(huì)被修改為-1000或者-2000等其他值,這樣的bug顯然是不可被接受的。

有并發(fā)經(jīng)驗(yàn)的應(yīng)該都知道需要通過(guò)鎖資源可以避免這個(gè)情況,InnoDB也是通過(guò)加來(lái)處理的。

redolog不完整

通過(guò)上文可以知道,InnoDB是通過(guò)「雙寫緩沖」、「Redo Log」等機(jī)制保證數(shù)據(jù)不丟失的。

這種情況下,假設(shè)第一條sql執(zhí)行成功并且對(duì)應(yīng)的redo log已經(jīng)被刷新到磁盤中,但是第二條sql執(zhí)行失敗或者M(jìn)ySQL服務(wù)宕機(jī)導(dǎo)致其redolog未刷新到磁盤,那么在下次啟動(dòng)恢復(fù)時(shí),就會(huì)發(fā)生數(shù)據(jù)不一致了。如下圖

在這里插入圖片描述

sql示例的第一條執(zhí)行結(jié)果通過(guò)redolog恢復(fù)了,但是第二條的redolog隨著宕機(jī)丟失了,于是乎造成了數(shù)據(jù)的不一致。(redo log的刷盤機(jī)制和構(gòu)建臟頁(yè)可以通過(guò)上文進(jìn)行了解。)

對(duì)于這種情況,InnoDB是通過(guò)上文提到的「Undo Log」來(lái)解決的。

binlog&redolog不一致

我們知道,binlog中記錄了所有對(duì)數(shù)據(jù)更新的原始sql,以便數(shù)據(jù)備份恢復(fù)、主從復(fù)制。與redolog不一樣的是binlog屬于MySQL server層,而redolog是InnoDB的機(jī)制,用于故障恢復(fù),兩者并不沖突,這里不過(guò)多贅述。

雖然不沖突,但是要保證兩者在事務(wù)提交后都可以持久化到磁盤,不然就會(huì)在主從復(fù)制的時(shí)候出現(xiàn)數(shù)據(jù)不一致現(xiàn)象,如下圖

在這里插入圖片描述

只要binlog和redolog有一方?jīng)]有同步持久到磁盤都會(huì)發(fā)生類似現(xiàn)象。針對(duì)這種情況MySQL是通過(guò)兩階段提交解決的。

以上就是DML在執(zhí)行過(guò)程中可能出現(xiàn)不一致的環(huán)節(jié)(沒(méi)有想到的歡迎評(píng)論交流)。接下來(lái)具體看一下InnoDB針對(duì)以上幾種情況是如何處理解決,從而保證數(shù)據(jù)一致性的。

MySQL解決不一致方案

加鎖解決并發(fā)沖突

鎖沒(méi)有什么好說(shuō)的,innoDB根據(jù)隔離級(jí)別決定是否用鎖(當(dāng)然,還有server層的表鎖什么的這里不展開)。這里就演示下在隔離級(jí)別REPEATABLE-READ下,鎖在SQL執(zhí)行中的具體作用和效果。

當(dāng)在第一個(gè)事務(wù)中執(zhí)行 update account set balance=balance-4000 where user='A' and balance >= 4000; 時(shí),其他事務(wù)不能對(duì)user為’A’的記錄進(jìn)行更新。如下圖,當(dāng)?shù)诙€(gè)事務(wù)窗口執(zhí)行 update account set balance=balance-1000 where user='A' and balance >= 1000; 時(shí)會(huì)被阻塞住,直到第一個(gè)事務(wù)提交或者超時(shí)。

在這里插入圖片描述

這個(gè)時(shí)候可以通過(guò) select * from sys.innodb_lock_waits ; 查看一下鎖的相關(guān)信息

在這里插入圖片描述

這里的locked_type是RECORD,也就是行記錄鎖,還有一個(gè)是間隙鎖。

間隙鎖的作用是保證某個(gè)范圍內(nèi)的數(shù)據(jù)在鎖定情況下不會(huì)發(fā)生任何變化。比如,當(dāng)?shù)谝粋€(gè)事務(wù)執(zhí)行update account set balance=balance-100 where id between 7 and 9;后,第二個(gè)事務(wù)在執(zhí)行INSERT INTO account (id, user,balance) VALUES (8, 'ABD',5000);時(shí)會(huì)阻塞,但是執(zhí)行 INSERT INTO account (id, user,balance) VALUES (16, 'ABDD',5000);會(huì)成功執(zhí)行,因?yàn)椴迦雐d為16的行數(shù)據(jù)不會(huì)影響到7~9之間的數(shù)據(jù)。這個(gè)時(shí)候去查看select * from sys.innodb_lock_waits;時(shí)會(huì)發(fā)現(xiàn)waiting_lock_mode值為 X,GAP(間隙)。

在這里插入圖片描述

所以說(shuō),鎖避免了事務(wù)的并發(fā)訪問(wèn)導(dǎo)致的數(shù)據(jù)不一致。

undolog解決redolog不完整

InnoDB在因sql執(zhí)行失敗或者M(jìn)ySQL服務(wù)宕機(jī)導(dǎo)致redolog不完整從而出現(xiàn)數(shù)據(jù)不一致是這么解決的:

  • 在更新數(shù)據(jù)頁(yè)之前,InnoDB會(huì)先將數(shù)據(jù)當(dāng)前的狀態(tài)記錄在「Undo Log」中。
  • 之后,再將更新后的相關(guān)數(shù)據(jù)記錄到「Redo Log」中。

這樣的話,不論出現(xiàn)哪種情況都可以通過(guò)undo log將數(shù)據(jù)回滾并保持一致,這個(gè)就是經(jīng)常提到的原子性以及「回滾」操作。

就如上圖(redo log不完整環(huán)節(jié)),加上Undo log之后數(shù)據(jù)狀態(tài)如下圖

在這里插入圖片描述

圖中加了行記錄的隱藏字段事務(wù)ID和回滾指針以及undo log頁(yè)和undo的redo。

undo log 記錄的就是user='A’和‘B’事務(wù)提交前的數(shù)據(jù),各為4000。

redo log 中會(huì)記錄所有的更新操作,包括undo,因?yàn)閡ndo記錄的也是更新語(yǔ)句。需要說(shuō)一下,這里記錄的undo是演示使用,對(duì)于一條update操作,真正的undo會(huì)記錄一條delete和一條insert操作,原因上文有介紹。

為什么redo log會(huì)記錄undo

undo log是以頁(yè)為單位,跟隨頁(yè)的刷新機(jī)制,會(huì)存在丟失的情況,所以在記錄undo后也會(huì)將該undo記錄到redo,避免undo丟失,一旦undo丟失就回滾不了了。

有了undo log后,假設(shè)第二條sql執(zhí)行失敗,這個(gè)時(shí)候就會(huì)通過(guò)行記錄中的事務(wù)ID(txidx)和回滾指針(roll_pointx、roll_pointx1)去undolog中找對(duì)應(yīng)的回滾操作(如圖中的 ‘**回滾指針’**箭頭),最終將事務(wù)回滾保證原子性和一致性。

針對(duì)上圖的狀態(tài),如果發(fā)生宕機(jī),那么在重新MySQL服務(wù)時(shí),會(huì)有兩個(gè)操作:

  • 會(huì)先通過(guò)redo log構(gòu)建「臟頁(yè)」。
  • 根據(jù)redo log中記錄的事務(wù)提交狀態(tài)來(lái)決定是否回滾。

如圖

在這里插入圖片描述

當(dāng)前user='A’的事務(wù)狀態(tài)為prepare,所以需要進(jìn)行回滾操作?;貪L流程是這樣的:

  • 根據(jù)數(shù)據(jù)中該記錄的事務(wù)ID(txidx)在undolog中找對(duì)應(yīng)的回滾操作。
  • 發(fā)現(xiàn)事務(wù)ID有兩個(gè)undo操作,user='A’和‘B’的。
  • 執(zhí)行undo操作,將數(shù)據(jù)頁(yè)中的記錄回滾至事務(wù)提交前狀態(tài)。

最終的結(jié)果就是user='A’和‘B’的balance會(huì)回滾到4000。

所以說(shuō),undo避免了事務(wù)或者宕機(jī)的異常導(dǎo)致的數(shù)據(jù)不一致。

XA兩階段提交解決binlog和redolog的不一致

redo log中的事務(wù)狀態(tài)不僅在這里起到作用,在binlog和redolog的一致上,同樣是通過(guò)這個(gè)狀態(tài)來(lái)判斷并且決定是否需要回滾。

這個(gè)就不得不說(shuō)到MySQL的XA兩階段提交協(xié)議了,在這之前,我一直以為XA是運(yùn)用到MySQL與外部應(yīng)用的,沒(méi)想到是應(yīng)用在MySQL內(nèi)部的。不過(guò)分布式事務(wù)嘛,原理基本上都一樣。

XA的兩階段分別是prepare和commit,在事務(wù)提交前,redolog中記錄的狀態(tài)都是prepare,當(dāng)事務(wù)提交后,該狀態(tài)就會(huì)被更新為commit,同時(shí)將XID寫入到對(duì)應(yīng)的binlog中并刷新到磁盤。如下圖

在這里插入圖片描述

這樣的話,如果發(fā)生宕機(jī),下次啟動(dòng)時(shí)可以根據(jù)redolog中的狀態(tài)以及XID去binlog中查找,如果存在意味著兩者一致,不存在就進(jìn)行回滾操作。

所以說(shuō),XA兩階段提交保證了binlog和redolog邏輯一致,從而避免主從節(jié)點(diǎn)的數(shù)據(jù)不一致。

總結(jié)

MySQL一致性的保證基本上涉及到InnoDB存儲(chǔ)引擎的各個(gè)組件,「Buffer Pool」、「Log Buffer」、「Redo Log」、「Undo Log」等,還有DML操作的流程、鎖、故障恢復(fù)等功能。最后再總結(jié)下MySQL是如何保證一致性的。

  • 對(duì)于并發(fā)操作帶來(lái)的數(shù)據(jù)不一致性問(wèn)題,InnoDB通過(guò)鎖來(lái)解決。
  • 對(duì)于可能會(huì)發(fā)生的redolog不完整的情況,InnoDB通過(guò)Undo Log來(lái)解決。
  • 對(duì)于redolog&binlog不一致帶來(lái)的主從節(jié)點(diǎn)數(shù)據(jù)不一致,MySQL是通過(guò)XA兩階段提交來(lái)解決。

以上就是詳解MySQL如何保證數(shù)據(jù)一致性的詳細(xì)內(nèi)容,更多關(guān)于MySQL保證數(shù)據(jù)一致性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • MySQL主從同步設(shè)置中主服務(wù)器二進(jìn)制日志無(wú)法開啟的問(wèn)題

    MySQL主從同步設(shè)置中主服務(wù)器二進(jìn)制日志無(wú)法開啟的問(wèn)題

    這篇文章主要介紹了MySQL主從同步設(shè)置中主服務(wù)器二進(jìn)制日志無(wú)法開啟的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • mysql實(shí)現(xiàn)sequence功能的代碼

    mysql實(shí)現(xiàn)sequence功能的代碼

    今天小編就為大家分享一篇關(guān)于mysql實(shí)現(xiàn)sequence功能的代碼,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • MySQL?EXPLAIN用法實(shí)例深度詳解

    MySQL?EXPLAIN用法實(shí)例深度詳解

    EXPLAIN是MySQL提供的性能分析工具,用于查看SQL查詢的執(zhí)行計(jì)劃,這篇文章主要介紹了MySQL EXPLAIN用法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2026-04-04
  • MySQL?5.7中NULL與‘?‘空字符值的多維度分析(詳解)

    MySQL?5.7中NULL與‘?‘空字符值的多維度分析(詳解)

    在數(shù)據(jù)庫(kù)設(shè)計(jì)和開發(fā)過(guò)程中,正確理解和使用NULL值對(duì)于確保數(shù)據(jù)質(zhì)量和查詢效率至關(guān)重要,本文將從多個(gè)維度對(duì)NULL值進(jìn)行深入分析,并與空字符串''以及其他控制進(jìn)行對(duì)比,旨在為讀者提供一個(gè)全面而清晰的理解,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • MySQL與Mongo簡(jiǎn)單的查詢實(shí)例代碼

    MySQL與Mongo簡(jiǎn)單的查詢實(shí)例代碼

    本文通過(guò)一個(gè)實(shí)例給大家用MySQL和mongodb分別寫一個(gè)查詢,本文圖片并茂給大家介紹的非常詳細(xì),感興趣的朋友參考下吧
    2016-10-10
  • 三種東西永遠(yuǎn)不要放到mysql數(shù)據(jù)庫(kù)里

    三種東西永遠(yuǎn)不要放到mysql數(shù)據(jù)庫(kù)里

    這篇文章主要介紹了mysql數(shù)據(jù)庫(kù)不能存儲(chǔ)的三樣?xùn)|西,需要的朋友可以參考下
    2014-06-06
  • MySQL高級(jí)查詢之JOIN、子查詢、窗口函數(shù)實(shí)際案例

    MySQL高級(jí)查詢之JOIN、子查詢、窗口函數(shù)實(shí)際案例

    這篇文章主要介紹了MySQL高級(jí)查詢之JOIN、子查詢、窗口函數(shù)實(shí)際案例的相關(guān)資料,JOIN用于多表關(guān)聯(lián)查詢,子查詢用于數(shù)據(jù)篩選和過(guò)濾,窗口函數(shù)則提供靈活的數(shù)據(jù)統(tǒng)計(jì)和排名功能,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-04-04
  • SQL GROUP BY 詳解及簡(jiǎn)單實(shí)例

    SQL GROUP BY 詳解及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了SQL GROUP BY 詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • cmd中MySQL中文數(shù)據(jù)亂碼問(wèn)題解決方法

    cmd中MySQL中文數(shù)據(jù)亂碼問(wèn)題解決方法

    MySQL是默認(rèn)utf8編碼的,所建數(shù)據(jù)庫(kù)也是設(shè)置utf8編碼,使用程序可以新增中文數(shù)據(jù),在cmd中使用SQL語(yǔ)句新增數(shù)據(jù)則報(bào)錯(cuò),有類似情況的朋友可以參考下本文
    2014-02-02
  • MySQL創(chuàng)建表操作命令分享

    MySQL創(chuàng)建表操作命令分享

    這篇文章主要介紹了MySQL創(chuàng)建表操作命令分享,分享內(nèi)容有查看所有表,創(chuàng)建表和MySQL支持的常用數(shù)據(jù)類型,具有一的參考價(jià)值,需要的小伙伴可以參考一下
    2022-03-03

最新評(píng)論

阿克陶县| 元朗区| 云阳县| 贵德县| 越西县| 伊通| 定安县| 卢氏县| 金秀| 忻州市| 资兴市| 昌平区| 南陵县| 呈贡县| 玛沁县| 泾阳县| 长宁区| 宿州市| 渭源县| 鄯善县| 台南县| 彩票| 达尔| 南皮县| 丹阳市| 丹东市| 克东县| 当涂县| 舟曲县| 公安县| 怀远县| 津南区| 马边| 镇安县| 岳普湖县| 琼中| 梓潼县| 合山市| 德清县| 内丘县| 苍溪县|