圖解mysql事務實現(xiàn)原理

什么是事務指么?
事務是一組原子性的sql語句旬薯,或者說是一個獨立的工作單元效诅。事務有四個特性布隔,原子性(Atomicity),一致性(Consistency),隔離型(Isolation)以及持久性(Durability)。今天想跟大家一起研究下事務內(nèi)部到底是怎么實現(xiàn)的澎迎。
事務無非是要做到可靠性以及并發(fā)處理
可靠性:數(shù)據(jù)庫要保證當insert或update操作時拋異陈睿或者數(shù)據(jù)庫crash的時候需要保障數(shù)據(jù)的操作前后的一致,想要做到這個夹供,我需要知道我修改之前和修改之后的狀態(tài)灵份,所以就有了undo log和redo log。
并發(fā)處理:也就是說當多個并發(fā)請求過來罩引,并且其中有一個請求是對數(shù)據(jù)修改操作的時候會有影響各吨,為了避免讀到臟數(shù)據(jù)枝笨,所以需要對事務之間的讀寫進行隔離袁铐,至于隔離到啥程度得看業(yè)務系統(tǒng)的場景了,實現(xiàn)這個就得用MySQL 的隔離級別横浑。
下面我首先講實現(xiàn)事務功能的三個技術剔桨,分別是日志文件(redo log 和 undo log),鎖技術以及MVCC徙融,然后再講事務的實現(xiàn)原理洒缀,包括原子性是怎么實現(xiàn)的,隔離型是怎么實現(xiàn)的等等欺冀。最后在做一個總結(jié)树绩,希望大家能夠耐心看完
redo log與undo log介紹
mysql鎖技術以及MVCC基礎
事務的實現(xiàn)原理
總結(jié)

一、redo log 與 undo log介紹

1.redo log
什么是redo log ?
redo log叫做重做日志隐轩,用來實現(xiàn)事務的持久性饺饭。該日志文件由兩部分組成:重做日志緩沖(redo log buffer)以及重做日志文件(redo log),前者是在內(nèi)存中,后者在磁盤中职车。當事務提交之后會把所有修改信息都會存到該日志中瘫俊。
redo log 有什么作用?
mysql 為了提升性能不會把每次的修改都實時同步到磁盤悴灵,而是會先存到Boffer Pool(緩沖池)里頭扛芽,把這個當作緩存來用。然后使用后臺線程去做緩沖池和磁盤之間的同步积瞒。
那么問題來了川尖,如果還沒來的同步的時候宕機或斷電了怎么辦?還沒來得及執(zhí)行上面圖中紅色的操作茫孔。這樣會導致丟部分已提交事務的修改信息叮喳!
所以引入了redo log來記錄已成功提交事務的修改信息庐船,并且會把redo log持久化到磁盤,系統(tǒng)重啟之后在讀取redo log恢復最新數(shù)據(jù)嘲更。
總結(jié):
redo log是用來恢復數(shù)據(jù)的用于保障筐钟,已提交事務的持久化特性
2.undo log
什么是 undo log ?
undo log 叫做回滾日志赋朦,用于記錄數(shù)據(jù)被修改前的信息篓冲。他正好跟前面所說的重做日志所記錄的相反,重做日志記錄數(shù)據(jù)被修改后的信息宠哄。undo log主要記錄的是數(shù)據(jù)的邏輯變化壹将,為了在發(fā)生錯誤時回滾之前的操作,需要將之前的操作都記錄下來毛嫉,然后在發(fā)生錯誤時才可以回滾诽俯。
undo log 有什么作用?
undo log 記錄事務修改之前版本的數(shù)據(jù)信息承粤,因此假如由于系統(tǒng)錯誤或者rollback操作而回滾的話可以根據(jù)undo log的信息來進行回滾到?jīng)]被修改前的狀態(tài)暴区。
總結(jié):
undo log是用來回滾數(shù)據(jù)的用于保障未提交事務的原子性

二、mysql鎖技術以及MVCC基礎

1.mysql鎖技術
當有多個請求來讀取表中的數(shù)據(jù)時可以不采取任何操作辛臊,但是多個請求里有讀請求仙粱,又有修改請求時必須有一種措施來進行并發(fā)控制。不然很有可能會造成不一致彻舰。
讀寫鎖
解決上述問題很簡單伐割,只需用兩種鎖的組合來對讀寫請求進行控制即可,這兩種鎖被稱為:
共享鎖(shared lock),又叫做"讀鎖"
讀鎖是可以共享的刃唤,或者說多個讀請求可以共享一把鎖讀數(shù)據(jù)隔心,不會造成阻塞。
排他鎖(exclusive lock),又叫做"寫鎖"
寫鎖會排斥其他所有獲取鎖的請求尚胞,一直阻塞硬霍,直到寫入完成釋放鎖。

image.png

總結(jié)
通過讀寫鎖辐真,可以做到讀讀并行须尚,但不能做到寫讀,寫寫并行侍咱。事務的隔離性就是根據(jù)讀寫鎖來實現(xiàn)的D痛病!
2.MVCC基礎
MVCC (MultiVersion Concurrency Control) 叫做多版本并發(fā)控制楔脯。
InnoDB的 MVCC 撩轰,是通過在每行記錄的后面保存兩個隱藏的列來實現(xiàn)的。這兩個列, 一個保存了行的創(chuàng)建時間堪嫂,一個保存了行的過期時間偎箫, 當然存儲的并不是實際的時間值,而是系統(tǒng)版本號皆串。
以上片段摘自《高性能Mysql》這本書對MVCC的定義淹办。他的主要實現(xiàn)思想是通過數(shù)據(jù)多版本來做到讀寫分離。從而實現(xiàn)不加鎖讀進而做到讀寫并行恶复。
MVCC在mysql中的實現(xiàn)依賴的是undo log與read view
undo log :undo log 中記錄某行數(shù)據(jù)的多個版本的數(shù)據(jù)怜森。
read view :用來判斷當前版本數(shù)據(jù)的可見性
image.png

三:事務的實現(xiàn)

前面講的重做日志,回滾日志以及鎖技術就是實現(xiàn)事務的基礎谤牡。
事務的原子性是通過undo log來實現(xiàn)的副硅。
事務的持久性是通過redo log來實現(xiàn)的。
事務的隔離性是通過 (讀寫鎖+MVCC)來實現(xiàn)的翅萤。
事務的一致性是通過原子性恐疲,持久性,隔離性來實現(xiàn)的L酌础E嗉骸!
1.原子性的實現(xiàn)
什么是原子性:
一個事務必須被視為不可分割的最小工作單位违诗,一個事務中的所有操作要么全部成功提交漱凝,要么全部失敗回滾疮蹦,對于一個事務來說不可能只執(zhí)行其中的部分操作诸迟,這就是事務的原子性。
上面這段話取自《高性能MySQL》這本書對原子性的定義愕乎,原子性可以概括為就是要實現(xiàn)要么全部失敗阵苇,要么全部成功。
以上概念相信大家伙兒都了解感论,那么數(shù)據(jù)庫是怎么實現(xiàn)的呢绅项? 就是通過回滾操作。 所謂回滾操作就是當發(fā)生錯誤異潮纫蓿或者顯式的執(zhí)行rollback語句時需要把數(shù)據(jù)還原到原先的模樣快耿,所以這時候就需要用到undo log來進行回滾,接下來看一下undo log在實現(xiàn)事務原子性時怎么發(fā)揮作用的
1.1 undo log 的生成
假設有兩個表 bank和finance芳绩,表中原始數(shù)據(jù)如圖所示掀亥,當進行插入,刪除以及更新操作時生成的undo log如下面圖所示:

image.png

image.png

從上圖可以了解到數(shù)據(jù)的變更都伴隨著回滾日志的產(chǎn)生:
(1) 產(chǎn)生了被修改前數(shù)據(jù)(zhangsan,1000) 的回滾日志
(2) 產(chǎn)生了被修改前數(shù)據(jù)(zhangsan,0) 的回滾日志
根據(jù)上面流程可以得出如下結(jié)論:
1.每條數(shù)據(jù)變更(insert/update/delete)操作都伴隨一條undo log的生成,并且回滾日志必須先于數(shù)據(jù)持久化到磁盤上
2.所謂的回滾就是根據(jù)回滾日志做逆向操作妥色,比如delete的逆向操作為insert搪花,insert的逆向操作為delete,update的逆向為update等。
1.2 根據(jù)undo log 進行回滾
為了做到同時成功或者失敗撮竿,當系統(tǒng)發(fā)生錯誤或者執(zhí)行rollback操作時需要根據(jù)undo log 進行回滾
image.png

回滾操作就是要還原到原來的狀態(tài)吮便,undo log記錄了數(shù)據(jù)被修改前的信息以及新增和被刪除的數(shù)據(jù)信息,根據(jù)undo log生成回滾語句幢踏,比如:
(1) 如果在回滾日志里有新增數(shù)據(jù)記錄髓需,則生成刪除該條的語句
(2) 如果在回滾日志里有刪除數(shù)據(jù)記錄,則生成生成該條的語句
(3) 如果在回滾日志里有修改數(shù)據(jù)記錄房蝉,則生成修改到原先數(shù)據(jù)的語句
2.持久性的實現(xiàn)
事務一旦提交授账,其所作做的修改會永久保存到數(shù)據(jù)庫中,此時即使系統(tǒng)崩潰修改的數(shù)據(jù)也不會丟失惨驶。
先了解一下MySQL的數(shù)據(jù)存儲機制白热,MySQL的表數(shù)據(jù)是存放在磁盤上的,因此想要存取的時候都要經(jīng)歷磁盤IO,然而即使是使用SSD磁盤IO也是非常消耗性能的粗卜。 為此屋确,為了提升性能InnoDB提供了緩沖池(Buffer Pool),Buffer Pool中包含了磁盤數(shù)據(jù)頁的映射续扔,可以當做緩存來使用:
讀數(shù)據(jù):會首先從緩沖池中讀取攻臀,如果緩沖池中沒有,則從磁盤讀取在放入緩沖池纱昧;
寫數(shù)據(jù):會首先寫入緩沖池刨啸,緩沖池中的數(shù)據(jù)會定期同步到磁盤中;
上面這種緩沖池的措施雖然在性能方面帶來了質(zhì)的飛躍识脆,但是它也帶來了新的問題设联,當MySQL系統(tǒng)宕機,斷電的時候可能會丟數(shù)據(jù)W莆妗@肜!
因為我們的數(shù)據(jù)已經(jīng)提交了悉稠,但此時是在緩沖池里頭宫蛆,還沒來得及在磁盤持久化,所以我們急需一種機制需要存一下已提交事務的數(shù)據(jù)的猛,為恢復數(shù)據(jù)使用耀盗。
于是 redo log就派上用場了。下面看下redo log是什么時候產(chǎn)生的
既然redo log也需要存儲卦尊,也涉及磁盤IO為啥還用它叛拷?
image.png

(1)redo log 的存儲是順序存儲,而緩存同步是隨機操作猫牡。
(2)緩存同步是以數(shù)據(jù)頁為單位的胡诗,每次傳輸?shù)臄?shù)據(jù)大小大于redo log邓线。
3.隔離性實現(xiàn)
隔離性是事務ACID特性里最復雜的一個。在SQL標準里定義了四種隔離級別煌恢,每一種級別都規(guī)定一個事務中的修改骇陈,哪些是事務之間可見的,哪些是不可見的瑰抵。級別越低的隔離級別可以執(zhí)行越高的并發(fā)你雌,但同時實現(xiàn)復雜度以及開銷也越大。
Mysql 隔離級別有以下四種(級別由低到高):
READ UNCOMMITED (未提交讀)
READ COMMITED (提交讀)
REPEATABLE READ (可重復讀)
SERIALIZABLE (可重復讀)
只要徹底理解了隔離級別以及他的實現(xiàn)原理就相當于理解了ACID里的隔離型二汛。前面說過原子性婿崭,隔離性,持久性的目的都是為了要做到一致性肴颊,但隔離型跟其他兩個有所區(qū)別氓栈,原子性和持久性是為了要實現(xiàn)數(shù)據(jù)的可性保障靠,比如要做到宕機后的恢復婿着,以及錯誤后的回滾授瘦。
那么隔離性是要做到什么呢? ** 隔離性是要管理多個并發(fā)讀寫請求的訪問順序竟宋。** 這種順序包括串行或者是并行
說明一點提完,寫請求不僅僅是指insert操作,又包括update操作丘侠。
image.png

總之徒欣,從隔離性的實現(xiàn)可以看出這是一場數(shù)據(jù)的可靠性與性能之間的權(quán)衡。
可靠性性高的蜗字,并發(fā)性能低(比如 Serializable)
可靠性低的打肝,并發(fā)性能高(比如 Read Uncommited)
READ UNCOMMITTED
在READ UNCOMMITTED隔離級別下,事務中的修改即使還沒提交秽澳,對其他事務是可見的闯睹。事務可以讀取未提交的數(shù)據(jù),造成臟讀担神。因為讀不會加任何鎖,所以寫操作在讀的過程中修改數(shù)據(jù)始花,所以會造成臟讀。好處是可以提升并發(fā)處理性能酷宵,能做到讀寫并行亥贸。
換句話說,讀的操作不能排斥寫請求浇垦。
image.png

優(yōu)點:讀寫并行默垄,性能高
缺點:造成臟讀
READ COMMITTED
一個事務的修改在他提交之前的所有修改,對其他事務都是不可見的鹃操。其他事務能讀到已提交的修改變化赴背。在很多場景下這種邏輯是可以接受的耸三。
InnoDB在 READ COMMITTED浇揩,使用排它鎖,讀取數(shù)據(jù)不加鎖而是使用了MVCC機制。或者換句話說他采用了讀寫分離機制缚陷。
但是該級別會產(chǎn)生不可重讀以及幻讀問題。
什么是不可重讀?
在一個事務內(nèi)多次讀取的結(jié)果不一樣窜护。
為什么會產(chǎn)生不可重復讀非春?
這跟 READ COMMITTED 級別下的MVCC機制有關系敌完,在該隔離級別下每次 select的時候新生成一個版本號蠢挡,所以每次select的時候讀的不是一個副本而是不同的副本。
在每次select之間有其他事務更新了我們讀取的數(shù)據(jù)并提交了勤家,那就出現(xiàn)了不可重復讀乐设。
image.png

REPEATABLE READ(Mysql默認隔離級別)
在一個事務內(nèi)的多次讀取的結(jié)果是一樣的市咆。這種級別下可以避免扳抽,臟讀揣苏,不可重復讀等查詢問題骤竹。mysql 有兩種機制可以達到這種隔離級別的效果往毡,分別是采用讀寫鎖以及MVCC。
采用讀寫鎖實現(xiàn)
image.png

為什么能可重復度递宅?只要沒釋放讀鎖,在次讀的時候還是可以讀到第一次讀的數(shù)據(jù)俐填。
優(yōu)點:實現(xiàn)起來簡單
缺點:無法做到讀寫并行
采用MVCC實現(xiàn)
image.png

為什么能可重復度?因為多次讀取只生成一個版本驶悟,讀到的自然是相同數(shù)據(jù)豺憔。
優(yōu)點:讀寫并行
缺點:實現(xiàn)的復雜度高
但是在該隔離級別下仍會存在幻讀的問題.
SERIALIZABLE
該隔離級別理解起來最簡單恭应,實現(xiàn)也最單胆屿。在隔離級別下除了不會造成數(shù)據(jù)不一致問題憎兽,沒其他優(yōu)點。
image.png

--摘自《高性能Mysql》
總結(jié)
實現(xiàn)事務采取了哪些技術以及思想揪阿?
原子性:使用undo log黑毅,從而達到回滾
持久性:使用redo log缚去,從而達到故障后恢復
隔離性:使用鎖以及MVCC,運用的優(yōu)化思想有讀寫分離琼开,讀讀并行渣刷,讀寫并行
一致性:通過回滾碌嘀,以及恢復穆律,和在并發(fā)環(huán)境下的隔離做到一致性辅髓。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挺举,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖硝皂,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锐秦,居然都是意外死亡酱床,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓶蝴,“玉大人,你說我怎么就攤上這事珠叔×固疲” “怎么了读整?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵的榛,是天一觀的道長。 經(jīng)常有香客問我妆丘,道長,這世上最難降的妖魔是什么愤惰? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任宦言,我火速辦了婚禮扇单,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奠旺。我一直安慰自己蜘澜,他們只是感情好,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布响疚。 她就那樣靜靜地躺著鄙信,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稽寒。 梳的紋絲不亂的頭發(fā)上扮碧,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機與錄音,去河邊找鬼慎王。 笑死蚓土,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的赖淤。 我是一名探鬼主播蜀漆,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼咱旱!你這毒婦竟也來了确丢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤吐限,失蹤者是張志新(化名)和其女友劉穎鲜侥,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诸典,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡描函,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了狐粱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舀寓。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肌蜻,靈堂內(nèi)的尸體忽然破棺而出互墓,到底是詐尸還是另有隱情,我是刑警寧澤蒋搜,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布篡撵,位于F島的核電站,受9級特大地震影響齿诞,放射性物質(zhì)發(fā)生泄漏酸休。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一祷杈、第九天 我趴在偏房一處隱蔽的房頂上張望斑司。 院中可真熱鬧,春花似錦但汞、人聲如沸宿刮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽僵缺。三九已至,卻和暖如春踩叭,著一層夾襖步出監(jiān)牢的瞬間磕潮,已是汗流浹背翠胰。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留自脯,地道東北人之景。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像膏潮,于是被迫代替她去往敵國和親锻狗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359