淺談MySQL中是如何實現(xiàn)事務(wù)提交和回滾的
什么是事務(wù)
事務(wù)是由數(shù)據(jù)庫中一系列的訪問和更新組成的邏輯執(zhí)行單元
事務(wù)的邏輯單元中可以是一條SQL語句,也可以是一段SQL邏輯,這段邏輯要么全部執(zhí)行成功,要么全部執(zhí)行失敗
舉個最常見的例子,你早上出去買早餐,支付寶掃碼付款給早餐老板,這就是一個簡單的轉(zhuǎn)賬過程,會包含兩步
- 從你的支付寶賬戶扣款10元
- 早餐老板的賬戶增加10元
這兩步其中任何一部出現(xiàn)問題,都會導(dǎo)致整個賬務(wù)出現(xiàn)問題
- 假如你的支付寶賬戶扣款10元失敗,早餐老板的賬戶增加成功,那你就Happy了,相當(dāng)于馬云請你吃早餐了,O(∩_∩)O哈哈~
- 假如你的支付寶賬戶扣款10元成功,早餐老板的賬戶增加失敗,那你就悲劇了,早餐老板不會放過你,會讓你重新付款,相當(dāng)于你請馬云吃早餐了-_-?
事務(wù)就是用來保證一系列操作的原子性,上述兩步操作,要么全部執(zhí)行成功,要么全部執(zhí)行失敗
數(shù)據(jù)庫為了保證事務(wù)的原子性和持久性,引入了redo log和undo log
redo log
redo log是重做日志,通常是物理日志,記錄的是物理數(shù)據(jù)頁的修改,它用來恢復(fù)提交后的物理數(shù)據(jù)頁
如上圖所示,redo log分為兩部分:
- 內(nèi)存中的redo log Buffer是日志緩沖區(qū),這部分?jǐn)?shù)據(jù)是容易丟失的
- 磁盤上的redo log file是日志文件,這部分?jǐn)?shù)據(jù)已經(jīng)持久化到磁盤,不容易丟失
SQL操作數(shù)據(jù)庫之前,會先記錄重做日志,為了保證效率會先寫到日志緩沖區(qū)中(redo log Buffer),再通過緩沖區(qū)寫到磁盤文件中進(jìn)行持久化,既然有緩沖區(qū)說明數(shù)據(jù)不是實時寫到redo log file中的,那么假如redo log寫到緩沖區(qū)后,此時服務(wù)器斷電了,那redo log豈不是會丟失?
在MySQL中可以自已控制log buffer刷新到log file中的頻率,通過innodb_flush_log_at_trx_commit參數(shù)可以設(shè)置事務(wù)提交時log buffer如何保存到log file中,innodb_flush_log_at_trx_commit參數(shù)有3個值(0、1、2),表示三種不同的方式
- 為1表示事務(wù)每次提交都會將log buffer寫入到os buffer,并調(diào)用操作系統(tǒng)的fsync()方法將日志寫入log file,這種方式的好處是就算MySQL崩潰也不會丟數(shù)據(jù),redo log file保存了所有已提交事務(wù)的日志,MySQL重新啟動后會通過redo log file進(jìn)行恢復(fù)。但這種方式每次提交事務(wù)都會寫入磁盤,IO性能較差
- 為0表示事務(wù)提交時不會將log buffer寫入到os buffer中,而是每秒寫入os buffer然后調(diào)用fsync()方法將日志寫入log file,這種方式在MySQL系統(tǒng)崩潰時會丟失大約1秒鐘的數(shù)據(jù)
- 為2表示事務(wù)每次提交僅將log buffer寫入到os buffer中,然后每秒調(diào)用fsync()方法將日志寫入log file,這種方式在MySQL崩潰時也會丟失大約1秒鐘的數(shù)據(jù)
undo log
undo log是回滾日志,用來回滾行記錄到某個版本,undo log一般是邏輯日志,根據(jù)行的數(shù)據(jù)變化進(jìn)行記錄
undo log跟redo log一樣也是在SQL操作數(shù)據(jù)之前記錄的,也就是SQL操作先記錄日志,再進(jìn)行操作數(shù)據(jù)
如上圖所示,SQL操作之前會先記錄redo log、undo log到日志緩沖區(qū),日志緩沖區(qū)的數(shù)據(jù)會記錄到os buffer中,再通過調(diào)用fsync()方法將日志記錄到log file中
undo log記錄的是邏輯日志,可以簡單的理解為:當(dāng)insert一條記錄時,undo log會記錄一條對應(yīng)的delete語句;當(dāng)update一條語句時,undo log記錄的是一條與之操作相反的語句
當(dāng)事務(wù)需要回滾時,可以從undo log中找到相應(yīng)的內(nèi)容進(jìn)行回滾操作,回滾后數(shù)據(jù)恢復(fù)到操作之前的狀態(tài)
undo日志還有一個用途就是用來控制數(shù)據(jù)的多版本(MVCC),在《InnoDB存儲引擎中的鎖》一文中講到MVCC是通過讀取undo日志中數(shù)據(jù)的快照來進(jìn)行多版本控制的
undo log是采用段(segment)的方式來記錄的,每個undo操作在記錄的時候占用一個undo log segment。
另外,undo log也會產(chǎn)生redo log,因為undo log也要實現(xiàn)持久性保護(hù)
總結(jié)一下
MySQL中是如何實現(xiàn)事務(wù)提交和回滾的?
- 為了保證數(shù)據(jù)的持久性,數(shù)據(jù)庫在執(zhí)行SQL操作數(shù)據(jù)之前會先記錄redo log和undo log
- redo log是重做日志,通常是物理日志,記錄的是物理數(shù)據(jù)頁的修改,它用來恢復(fù)提交后的物理數(shù)據(jù)頁
- undo log是回滾日志,用來回滾行記錄到某個版本,undo log一般是邏輯日志,根據(jù)行的數(shù)據(jù)變化進(jìn)行記錄
- redo/undo log都是寫先寫到日志緩沖區(qū),再通過緩沖區(qū)寫到磁盤日志文件中進(jìn)行持久化保存
- undo日志還有一個用途就是用來控制數(shù)據(jù)的多版本(MVCC)
簡單理解就是:
- redo log是用來恢復(fù)數(shù)據(jù)的,用于保障已提交事務(wù)的持久性
- undo log是用來回滾事務(wù)的,用于保障未提交事務(wù)的原子性
到此這篇關(guān)于淺談MySQL中是如何實現(xiàn)事務(wù)提交和回滾的的文章就介紹到這了,更多相關(guān)MySQL 事務(wù)提交和回滾內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用IDEA創(chuàng)建Java Web項目并部署訪問的圖文教程
本文通過圖文并茂的形式給大家介紹了使用IDEA創(chuàng)建Java Web項目并部署訪問的教程,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-08-08Maven?Pom?文件中的隱式依賴導(dǎo)致Jar沖突問題
這篇文章主要介紹了Maven?Pom?文件中的隱式依賴導(dǎo)致Jar沖突問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12使用logstash同步mysql數(shù)據(jù)到elasticsearch實現(xiàn)
這篇文章主要為大家介紹了使用logstash同步mysql數(shù)據(jù)到elasticsearch實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Java替換中使用正則表達(dá)式實現(xiàn)中間模糊匹配的方法
今天小編就為大家分享一篇Java替換中使用正則表達(dá)式實現(xiàn)中間模糊匹配的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07idea快捷鍵生成getter和setter,有構(gòu)造參數(shù),無構(gòu)造參數(shù),重寫toString方式
這篇文章主要介紹了java之idea快捷鍵生成getter和setter,有構(gòu)造參數(shù),無構(gòu)造參數(shù),重寫toString方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11Java關(guān)鍵字instanceof用法及實現(xiàn)策略
instanceof 運算符是用來在運行時判斷對象是否是指定類及其父類的一個實例。這篇文章主要介紹了Java關(guān)鍵字instanceof用法解析,需要的朋友可以參考下2020-08-08