愛(ài)炫耀的數(shù)據(jù)庫(kù)老頭兒
1.數(shù)據(jù)庫(kù)老頭兒
我們這個(gè)世界很大, 生活著很多人,形形色色,各懷絕技。但是被公認(rèn)為最拽的一個(gè)卻是數(shù)據(jù)庫(kù)老頭兒,年齡挺大,每天都要炫耀幾遍他那關(guān)系型數(shù)據(jù)庫(kù), 那理論有著多么堅(jiān)實(shí)的數(shù)學(xué)基礎(chǔ),那關(guān)系運(yùn)算是多么地優(yōu)雅,事務(wù)管理是多么強(qiáng)大,還有他是多么地穩(wěn)定, 要不怎么他怎么能活這么久等等。
老頭兒有他拽的資本,因?yàn)槲覀冞@個(gè)系統(tǒng)的核心數(shù)據(jù)都是在老頭兒那里存放著, 例如用戶了,訂單了,交易了...... 我向別人打聽(tīng)過(guò), 這些數(shù)據(jù)已經(jīng)在老頭兒那里積累了20多年了, 最早的時(shí)候是Dephi, PowerBuider 這些上古的軟件寫的系統(tǒng)訪問(wèn), 后來(lái)慢慢轉(zhuǎn)到互聯(lián)網(wǎng),先用PHP訪問(wèn), 再后來(lái)變?yōu)镴ava。
看來(lái)最寶貴的東西是數(shù)據(jù), 外界系統(tǒng)可以變, 但是數(shù)據(jù)不能丟, 老頭兒守著這份財(cái)產(chǎn),生生地熬死了一代人,估計(jì)還會(huì)再熬死一代人。
2.事務(wù)
這一天老頭兒又在那里一邊喝酒,一邊“吹噓” 他的事務(wù)管理,說(shuō)些ACID之類我們都聽(tīng)不懂的外國(guó)話, 和數(shù)據(jù)庫(kù)經(jīng)常打交道的是年輕的小伙子Tomcat, 對(duì)于老頭兒,他比我們多了解那么一點(diǎn)點(diǎn)。
Tomcat端了一杯啤酒來(lái)到老頭兒桌前:“嗨,老頭兒,我知道你說(shuō)的事務(wù)有個(gè)重要的特性:原子性,就是說(shuō)在一個(gè)事務(wù)中不管有多少操作,都是要么全做,要么全不做,是這樣吧!”
“那是自然!”
“我很好奇,在執(zhí)行的操作過(guò)程中,如果還沒(méi)做完系統(tǒng)就崩潰了,或者斷電了,你怎么辦啊? 你怎么保證原子性?”
聽(tīng)到Tomcat問(wèn)了一個(gè)關(guān)鍵的問(wèn)題,酒館里的CPU阿甘, Ngnix, Spring, MyBatis 都圍了過(guò)來(lái),都想聽(tīng)聽(tīng)老頭兒的高見(jiàn) 。
“如果我還沒(méi)做完,系統(tǒng)就崩潰了,那系統(tǒng)重啟以后我就得做恢復(fù)操作啊。”
“怎么恢復(fù)啊? ” Tomcat 窮追不舍。
“你舉個(gè)例子,我給你分析分析 ” 老頭環(huán)顧四周,看到人們都圍了上來(lái),也來(lái)了一點(diǎn)興致 , “光講理論,這些小朋友們?cè)趺绰?tīng)得懂?”
“好啊, 比如旺財(cái)有200塊錢, 小強(qiáng)有50 塊錢,現(xiàn)在旺財(cái)要給小強(qiáng)轉(zhuǎn)賬,假設(shè)轉(zhuǎn)100塊吧, 你說(shuō)說(shuō),你是怎么實(shí)現(xiàn)要么不做,要么全做的。 ”
(1) 開(kāi)始事務(wù) T1 (假設(shè)T1是個(gè)事務(wù)的內(nèi)部編號(hào))
(2) 旺財(cái)余額 = 旺財(cái)余額 -100
(3) 小強(qiáng)余額 = 小強(qiáng)余額 + 100
(4) 提交事務(wù) T1
CPU阿甘插了一嘴說(shuō): “雖然這些都是我在做計(jì)算,但是這些計(jì)算結(jié)果都是先存在內(nèi)存中的, 內(nèi)存那家伙一斷電啥都忘了, 如果第三步還沒(méi)執(zhí)行完就斷電了, 那不就完蛋了。”
數(shù)據(jù)庫(kù)老頭兒說(shuō): “雖然數(shù)據(jù)先在內(nèi)存中被計(jì)算出來(lái), 但是我是要寫入硬盤的數(shù)據(jù)庫(kù)文件的,知道不? ”
“你的數(shù)據(jù)緩沖區(qū)是啥意思?” 人群里有人問(wèn)道。
“老土! 連數(shù)據(jù)緩沖區(qū)都不知道! 我告訴你吧, 那個(gè)硬盤啊速度太慢了,比內(nèi)存慢個(gè)幾萬(wàn)倍,你說(shuō)我能每次操作都去寫硬盤嗎? 絕對(duì)不可能,所以CPU阿甘計(jì)算出的數(shù)據(jù)我會(huì)放到數(shù)據(jù)緩沖區(qū)里, 我會(huì)在合適的時(shí)候把數(shù)據(jù)緩沖區(qū)的內(nèi)容寫入硬盤的數(shù)據(jù)文件。 ”
“什么合適的時(shí)候?”
“那是我的緩沖管理器要做的事情了,想聽(tīng)嗎? 我再花兩天給你講講!”
3.Undo 日志
“算了算了, 我們還是先假定數(shù)據(jù)緩沖區(qū)能和硬盤的數(shù)據(jù)文件同步吧, 回到剛才的問(wèn)題,旺財(cái)在給小強(qiáng)轉(zhuǎn)賬, 第二步執(zhí)行完了,旺財(cái)?shù)挠囝~變成了100塊 (200-100), 假設(shè)已經(jīng)寫入了硬盤文件, 現(xiàn)在斷電了, 小強(qiáng)的余額有沒(méi)有加上,系統(tǒng)的錢白白消失了100塊, 數(shù)據(jù)已經(jīng)不一致了, 你怎么辦?” Tomcat把話題轉(zhuǎn)移回來(lái)。
“放心吧, 我會(huì)記錄日志的,我有個(gè)叫做Undo的日志文件,就是為了解決這個(gè)問(wèn)題的” 老頭兒喝了一口酒 ,準(zhǔn)備開(kāi)始放大招 “比如你說(shuō)的情況, 我會(huì)在我的日志文件中記錄下事務(wù)開(kāi)始之前的他倆賬號(hào)余額:
[事務(wù)T1, 旺財(cái)原有余額 , 200]
[事務(wù)T1, 小強(qiáng)原有余額, 50 ]
如果事務(wù)執(zhí)行到一半,就斷電了,那數(shù)據(jù)庫(kù)重啟以后我就根據(jù)undo的日志文件來(lái)恢復(fù)。”
“嗯,那要是系統(tǒng)恢復(fù)的過(guò)程中又?jǐn)嚯娏?,還得再次恢復(fù),那數(shù)據(jù)豈不變得一團(tuán)糟? ” CPU阿甘對(duì)斷電心有余悸。
“對(duì)啊對(duì)啊”, 周邊的人附和到。
“你們這些年輕人啊, 還是too simple, 你們仔細(xì)想想,即使我把旺財(cái)?shù)挠囝~和小強(qiáng)的余額恢復(fù)了100次,會(huì)有什么結(jié)果?”
“如果每次都試圖把旺財(cái)?shù)挠囝~設(shè)為200, 小強(qiáng)余額設(shè)為50, 做多少次都沒(méi)問(wèn)題, 因?yàn)樗麄z原來(lái)的余額就是那么多 !” Tomcat恍然大悟。
“這就叫做操作的冪等性,知道不? 我可以一直做恢復(fù),恢復(fù)過(guò)程中斷電也不怕,只要把恢復(fù)做完就行。” 老頭兒看到時(shí)機(jī)一到,立刻上升為理論。
“恢復(fù)數(shù)據(jù)的時(shí)候, 那你怎么才能知道一個(gè)事務(wù)沒(méi)有完成呢?” Tomcat接著問(wèn)道。
數(shù)據(jù)庫(kù)老頭兒對(duì)這個(gè)問(wèn)題似乎很滿意, 專門花點(diǎn)時(shí)間寫了幾行字:
[開(kāi)始事務(wù) T1]
[事務(wù)T1, 旺財(cái)原有余額,200]
[事務(wù)T1, 小強(qiáng)原有余額,50]
[提交事務(wù) T1]
“Undo日志文件中不僅僅只有余額, 事務(wù)的開(kāi)始和結(jié)束也會(huì)記錄,如果我在日志文件中看到了[提交事務(wù) T1], 或者 [回滾事務(wù) T1], 我就知道這個(gè)事務(wù)已經(jīng)結(jié)束,不用再去理會(huì)它了, 更不用去恢復(fù)。 如果我只看到 [開(kāi)始事務(wù) T1], 而找不到提交或回滾,那我就得恢復(fù)。比如下面這個(gè):”
[開(kāi)始事務(wù) T1]
[事務(wù)T1, 旺財(cái)原有余額,200]
[事務(wù)T1, 小強(qiáng)原有余額,50]
“特別是,” 老頭補(bǔ)充道, “ 我恢復(fù)以后, 需要在日志文件中加上一行 [回滾事務(wù) T1] , 這樣下一次恢復(fù)我就不用再考慮T1這個(gè)事務(wù)了。”
4獨(dú)門絕技
“不對(duì)吧, 你這個(gè)Undo日志文件會(huì)面臨和數(shù)據(jù)文件一樣的問(wèn)題, 都是需要加載到內(nèi)存才能讀寫, 要不然會(huì)太慢。 那要是連日志文件還沒(méi)寫好就斷電了,那不還是玩完?” Ngnix 目光如炬,向深層次挖掘。
這是個(gè)絕佳的問(wèn)題,大家紛紛把目光殺向數(shù)據(jù)庫(kù)老頭兒,希望這一次能把他打翻在地。
老頭兒鎮(zhèn)定自若,沒(méi)有回答,反而給大家拋出一個(gè)問(wèn)題:“你們想想,我什么時(shí)候應(yīng)該記錄Undo日志,什么時(shí)候把Undo日志寫入文件呢?”
“事務(wù)一開(kāi)始的時(shí)候就得把Undo日志寫入文件, 這樣最安全!”
老頭兒笑了笑說(shuō): “蠢材! 一開(kāi)始的時(shí)候我都不知道程序到底要操作那個(gè)字段,怎么記錄Undo日志,怎么寫入硬盤文件? ”
“那怎么辦啊? ”
“這就是我的獨(dú)門秘籍了, 我給大家舉個(gè)例子, 你們可要看仔細(xì)了, 我把日志記錄也放到了內(nèi)存的Undo日志緩沖區(qū),伺機(jī)寫入硬盤。”
“不知道你們這些小朋友看出一點(diǎn)門道兒沒(méi)有?” 老頭兒?jiǎn)柕馈?/p>
“讓我想想” Ngnix說(shuō), “如果系統(tǒng)在第4步和第5步之間崩潰,旺財(cái)?shù)挠囝~寫入了硬盤,但是小強(qiáng)的還沒(méi)寫入, 那Undo日志看起來(lái)是這樣的:
[開(kāi)始事務(wù) T1]
[事務(wù)T1, 旺財(cái)原有余額,200]
由于找不到事務(wù)結(jié)束的日志, 你會(huì)進(jìn)行恢復(fù)操作, 把旺財(cái)?shù)脑杏囝~給恢復(fù)了。 ”
Tomcat 接過(guò)來(lái)說(shuō):“如果是在第7步和第8步之間系統(tǒng)崩潰,旺財(cái)和小強(qiáng)的最新余額都寫入了硬盤,但是沒(méi)有提交事務(wù), 那Undo日志看起來(lái)是這樣的:
[開(kāi)始事務(wù) T1]
[事務(wù)T1, 旺財(cái)原有余額,200]
[事務(wù)T1, 小強(qiáng)原有余額,50]
由于沒(méi)有事務(wù)結(jié)束的日志,你也需要進(jìn)行恢復(fù),把旺財(cái)和小強(qiáng)的原有余額恢復(fù)成200和50 ”
CPU阿甘也不甘示弱說(shuō): “如果是在第8步和第9步之間系統(tǒng)崩潰, 旺財(cái)和小強(qiáng)的最新余額都寫入了硬盤, 也提交了事務(wù), 但是提交事務(wù)的操作沒(méi)有寫入U(xiǎn)ndo 日志, 所以Undo日志還是這樣:”
[開(kāi)始事務(wù) T1]
[事務(wù)T1, 旺財(cái)原有余額,200]
[事務(wù)T1, 小強(qiáng)原有余額,50]
由于沒(méi)有事務(wù)結(jié)束的日志,你還得需要進(jìn)行恢復(fù),把旺財(cái)和小強(qiáng)的原有余額恢復(fù)成200和50”
數(shù)據(jù)庫(kù)老頭笑瞇瞇的聽(tīng)著大家的分析,似乎非常的享受: “是不是可以應(yīng)付各種情況啊? 啊?”
大家紛紛點(diǎn)頭,佩服無(wú)比。
Tomcat都不叫老頭兒,改稱為老先生了: “ 老先生, 好像是有什么內(nèi)在的規(guī)律,您給說(shuō)說(shuō)!”
數(shù)據(jù)庫(kù)老頭兒無(wú)比得意, 興致勃勃地說(shuō), “這就是我的獨(dú)門秘籍了, 其實(shí)很簡(jiǎn)單了, 就兩條:
1. 在你把最新余額寫入硬盤之前, 一定要先把相關(guān)的Undo日志記錄寫入硬盤。 例如[事務(wù)T1, 旺財(cái)原有余額,200] 一定要在旺財(cái)?shù)男掠囝~=100寫入硬盤之前寫入。
2. [提交事務(wù) T1] 這樣的Undo日志記錄一定要在所有的新余額寫入硬盤之后再寫入。 有了這兩條的保證,我就可以高枕無(wú)憂了!, 比如說(shuō),換個(gè)操作次序也沒(méi)有問(wèn)題:”
【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)作者微信公眾號(hào)coderising獲取授權(quán)】