數(shù)據(jù)庫中的二階段提交和二階段鎖

二階段鎖

對于Innodb中的行鎖,實際上是在需要的時候才加模燥,但并不是不需要了就立即釋放,而是等著事務結(jié)束了才會釋放心肪。其實這句話就是二階段鎖的含義。因此硬鞍,如果再事務中需要鎖多個行戴已,需要把最可能造成鎖沖突、最可能影響并發(fā)度的鎖盡量往后放伐坏,這樣盡可能減少持有鎖的時間握联。

現(xiàn)在舉個例子:需要在美團app上買一張故宮的門票

  1. 從顧客的賬戶中扣除門票錢
  2. 給美團的賬戶中增加門票錢
  3. 記錄一條交易log

從上面的例子中可以看到,現(xiàn)在需要update兩條記錄纯露,insert一條記錄代芜。事務是一定需要的,不然一旦某條sql失敗钞速,會導致數(shù)據(jù)不一致問題嫡秕。那么這三條數(shù)據(jù)如何安排順序呢?

按照上面二階段鎖的定義昆咽,相關(guān)行級鎖應該持有時間最小屠升,所以這種背景下,兩個update一定要放在最后汇在,第三條放在第一。這似乎就已經(jīng)是比較好的解決方案亩鬼。

那下面這個例子:

現(xiàn)在要刪除10000行數(shù)據(jù)阿蝶,有以下幾種方案:

  1. 執(zhí)行sql:delete from T limit 10000;
  2. 一個連接中循環(huán)20次 delete from T limit 500;
  3. 20個連接中執(zhí)行delete from T limit 500;

這幾種方法哪個比較好呢?

  1. 根據(jù)二階段鎖玷过,占用這些行級鎖的時間很長筑煮,導致其他客戶端等待資源時間較長
  2. 長事務分成短事務,每次事務占用鎖的時間比較短袋马,其他客戶端等待時間較短秸应,可以提高并發(fā)度
  3. 人為制造所競爭,加劇并發(fā)量软啼,實際意義不大

二階段提交

二階段提交涉及到一個更新sql語句的處理流程和redo log和binlog

現(xiàn)在看下一條更新sql是如何執(zhí)行的

CREATE TABLE `new_table` (
  `id` int(11) NOT NULL,
  `num` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

現(xiàn)在要把id=1的這一行+1焰宣,會這么寫

update new_table set num = num + 1 where id=1

相關(guān)執(zhí)行流程

sql執(zhí)行流程

涉及到update操作的時候,會涉及到redo log和binlog

redo log

每次更新的時候盈罐,可以想一想闪唆,其實并不是每次都更立刻更新到磁盤上了,這樣的話IO很頻繁票顾,響應也會很慢,為了解決這個問題奠骄,出現(xiàn)了redo log。

當有一條記錄要更新的時候影锈,會先把記錄寫進redo log里面,并更新內(nèi)存鸭廷,這個時候更新就算完成了熔吗,就可以返回客戶端了。同事桅狠,innodb會在適當?shù)臅r候,將這個操作記錄更新到磁盤里面维雇,而這個往往是系統(tǒng)比較空閑的時候做的晒他。但是如果系統(tǒng)更新的頻率比較高,redo log寫滿了陨仅,該怎么辦?這個時候只能停止更新触徐,先把redo log的內(nèi)容刷到磁盤里面狐赡,把redo log清空

可以想象,把redo log里面的數(shù)據(jù)刷到磁盤這個過程是很痛苦的颖侄,因為磁盤IO比較高,所以這個時候所有的查詢更新操作孝鹊,都會有抖動展蒂,這種情況下也叫做刷臟頁苔咪,相關(guān)刷臟頁就不介紹了柳骄,可以看下面這個介紹

https://gsmtoday.github.io/2019/02/08/flush/

binlog

從上面執(zhí)行流程的圖可以看到,一個sql執(zhí)行過程中馆里,主要分為客戶端、server端、存儲引擎丙者。redo log是存儲引擎innodb特有的日志,binlog是server端特有的日志目锭。所以說纷捞,在使用過程中,如果數(shù)據(jù)庫異常重啟主儡,之前提交的記錄會在redo log中,因為redo log是存儲引擎級別的丰捷,所以記錄不會丟失寂汇,這個也叫做crash-safe

那么為啥會有兩部分日志?myIsam出現(xiàn)的比innodb早停巷,之前在server端是有binlog的,binlog做的是歸檔工作畔勤,臼膏,歸檔工作自然是沒有crash-safe能力,所以后來innodb用了redo log來實現(xiàn)crash-safe能力嚷硫。那么這兩個日志主要的區(qū)別是什么呢?

  1. redo log是存儲引擎級別的仔掸,是innodb特有的;binlog是server端持有的起暮,是所有引擎都有的功能
  2. redo log是物理日志,記錄的是在某個數(shù)據(jù)頁做了什么修改筒捺;binlog是邏輯日志纸厉,記錄的是這個語句的原始邏輯,如果是statement格式的話肯尺,記錄的是sql語句躯枢,如果是row格式的話,記錄的是行的內(nèi)容锄蹂,包含更新前更新后的
  3. redo log是循環(huán)寫的,空間固定(一般是4個g寨昙,1個g為一組)掀亩;binlog是可以追加寫入的,就是說binlog文件寫完會寫入下一個文件槽棍,不會覆蓋之前的記錄

下面介紹一下上面sql語句具體的執(zhí)行流程

  1. 首先找到id=1這行炼七。因為id是主鍵,所以直接走主鍵索引樹查找到對應的記錄即可
  2. 看下當前數(shù)據(jù)所在數(shù)據(jù)頁是否在內(nèi)存中豌拙,如果在內(nèi)存中,直接返回給執(zhí)行器按傅,如果沒有再內(nèi)存中胧卤,需要把當前數(shù)據(jù)頁加載到內(nèi)存中枝誊。還要看數(shù)據(jù)頁加載到內(nèi)存后容量是否足夠,如果不夠叶撒,需要刷臟頁
  3. 執(zhí)行器拿到存儲引擎給的數(shù)據(jù)耐版,把這個值+1,得到新的數(shù)據(jù)再寫會存儲引擎
  4. 存儲引擎把這部分數(shù)據(jù)更新到內(nèi)存中哪审,同時將這個更新記錄到redo log中(在第幾個數(shù)據(jù)頁把某個數(shù)據(jù)改為某個數(shù)據(jù))虑瀑,此時redo log處于prepare狀態(tài)舌狗,告訴執(zhí)行器執(zhí)行完成扔水,隨時可以提交事務
  5. 執(zhí)行器生成這個操作的binlog,把binlog寫入磁盤
  6. 執(zhí)行器調(diào)用引擎的提交事務接口主届,引擎把剛剛寫入的redo log改為commit狀態(tài)

其實前3步應該還比較好理解,后三步事務結(jié)束的時候君丁,分成了兩個狀態(tài)處理了

二階段提交

為什么要把事務的commit分成兩個階段呢将宪?從prepare->commit。這個主要是為了讓binlog和redo log的狀態(tài)是一致的印蔗。

如果不用二階段提交會是什么結(jié)果呢丑勤?是數(shù)據(jù)被存儲引擎更新到內(nèi)存后,是先寫binlog還是先commit redo log呢耙厚?

  1. 先寫binlog。如果在binlog寫完以后颜曾,server端crash,這就導致redo log還沒寫稠诲,那么如果系統(tǒng)恢復后诡曙,redo log并沒有記錄這行數(shù)據(jù)有改動,但是binlog記錄了這行數(shù)據(jù)+1劝萤,這就導致binlog恢復后多了一個事務慎璧,和原來庫中的值已經(jīng)不同了
  2. 先commit redo log。redo log commit后胸私,mysql進程異常重啟,binlog寫入失敗阔涉,日志備份就沒這個變化了瑰排。那以后如果使用binlog恢復長期的數(shù)據(jù),那就跟真實的數(shù)據(jù)出現(xiàn)出入了暖侨。

所以可見,如果不用二階段提交函荣,怎么樣都有可能出現(xiàn)數(shù)據(jù)不一致扳肛。那么為啥二階段可以保證?

上面第五步結(jié)束后金拒,系統(tǒng)server端crash沒有通知到存儲引擎,redo log沒有寫入资铡,但是prepare和binlog完整笤休,重啟后會自動commit。也就是說這個時候保存的是修改后的數(shù)據(jù)

上面第四步結(jié)束后店雅,由于沒有寫入binlog贞铣,所以會直接回滾。這樣binlog和redo log就一致了窍奋。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琳袄,一起剝皮案震驚了整個濱河市纺酸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖在张,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帮匾,死亡現(xiàn)場離奇詭異,居然都是意外死亡缸夹,警方通過查閱死者的電腦和手機虽惭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門蛇尚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芽唇,“玉大人,你說我怎么就攤上這事〈殷裕” “怎么了研侣?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長炮捧。 經(jīng)常有香客問我庶诡,道長,這世上最難降的妖魔是什么咆课? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任末誓,我火速辦了婚禮,結(jié)果婚禮上傀蚌,老公的妹妹穿的比我還像新娘基显。我一直安慰自己,他們只是感情好善炫,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布窜醉。 她就那樣靜靜地躺著榨惰,像睡著了一般琅催。 火紅的嫁衣襯著肌膚如雪藤抡。 梳的紋絲不亂的頭發(fā)上缠黍,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天语泽,我揣著相機與錄音,去河邊找鬼瓤漏。 笑死蝶俱,一個胖子當著我的面吹牛榨呆,可吹牛的內(nèi)容都是我干的积蜻。 我是一名探鬼主播竿拆,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼御板!你這毒婦竟也來了怠肋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤杈抢,失蹤者是張志新(化名)和其女友劉穎春感,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刽辙,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年朦乏,在試婚紗的時候發(fā)現(xiàn)自己被綠了呻疹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刽锤。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宋彼,靈堂內(nèi)的尸體忽然破棺而出宙暇,到底是詐尸還是另有隱情占贫,我是刑警寧澤先口,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站烫葬,受9級特大地震影響搭综,放射性物質(zhì)發(fā)生泄漏兑巾。R本人自食惡果不足惜蒋歌,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一修档、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧癣诱,春花似錦撕予、人聲如沸实抡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辣卒。三九已至荣茫,卻和暖如春啡莉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背该押。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奠蹬,地道東北人囤躁。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓僻他,卻偏偏與公主長得像满哪,于是被迫代替她去往敵國和親哨鸭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 什么是事務 事務是一條或多條數(shù)據(jù)庫操作語句的組合蕊蝗,具備ACID夸楣,4個特點豫喧。 原子性:要不全部成功,要不全部撤銷 隔...
    jiangmo閱讀 1,082評論 0 3
  • 最近碰到幾個業(yè)務場景涉兽,會遇到并發(fā)的問題。在單實例情況下拥诡,我們會通過java.util.concurrent包...
    菜鳥小玄閱讀 2,252評論 0 5
  • 我們就從一條 update 語句開始爽冕。 其實執(zhí)行流程和查詢流程一致前塔,只是最后執(zhí)行器執(zhí)行的是找到這條數(shù)據(jù)华弓,并進行更新...
    帥氣的名稱被占用閱讀 1,613評論 2 4
  • 12.19日精進:敬畏—進入—體驗—交給—持續(xù) 1,缺啥補啥迁霎,怕啥練啥考廉; 2,一切為我所用,所用為團隊家涮坐; 3袱讹,我...
    dangdangda_a512閱讀 191評論 0 0
  • 又是一年芳草綠征绸,依然好景舞春風。在這充滿生機渤弛、萌發(fā)活力的美好季節(jié)她肯,我們對新的一年懷抱新的憧憬,寄予新的期待籽前。春天枝哄,...
    喬一塵閱讀 622評論 0 1