怎么实现事务_你可能知道事务的四大特性,但是不一定知道“事务的实现原理”...
說(shuō)到數(shù)據(jù)庫(kù),那就一定會(huì)聊到事務(wù),事務(wù)也是面試中常問(wèn)的問(wèn)題,我們先來(lái)一個(gè)面試場(chǎng)景:
面試官:"事務(wù)的四大特性是什么?"我:"ACID,即原子性(Atomicity)、隔離性(Isolation)、持久性(Durability)、一致性(Consistency)!"面試官:"在 MySQL 數(shù)據(jù)庫(kù)的 InnoDB 引擎是怎么實(shí)現(xiàn)這四大特性的?"我:"這個(gè)...這個(gè)....,還真沒(méi)有了解過(guò)哎"面試官:"那我們就先這個(gè)吧,先回去吧,我們會(huì)通知你的~"這可能是比較常見(jiàn)的面試場(chǎng)景了,你也許回答到了事務(wù)的四大特性,但是不一定知道他的實(shí)現(xiàn)原理。今天我們就來(lái)一起打卡事務(wù)的四大特性和實(shí)現(xiàn)原理,對(duì)于原理的實(shí)現(xiàn),這篇文章只是粗略的介紹一下,更多的細(xì)節(jié)可以關(guān)注我后續(xù)的文章。
數(shù)據(jù)庫(kù)的事務(wù)有四大特性:原子性、隔離性、永久性、一致性,下面將介紹這四大特性的定義和在 InnoDB 引擎中是怎么實(shí)現(xiàn)的。
原子性
定義
一次操作是不可分割的,要么全部成功,要么全部失敗。比如我們的轉(zhuǎn)賬操作,不允許出款方成功,收款方失敗這種情況,要么都成功,要么多失敗,不可能出現(xiàn)中間狀態(tài)。
實(shí)現(xiàn)
InnoDB 引擎使用 undo log(歸滾日志)來(lái)保證原子性操作,你對(duì)數(shù)據(jù)庫(kù)的每一條數(shù)據(jù)的改動(dòng)(INSERT、DELETE、UPDATE)都會(huì)被記錄到 undo log 中,比如以下這些操作:
- 你插入一條記錄時(shí),至少要把這條記錄的主鍵值記下來(lái),之后回滾的時(shí)候只需要把這個(gè)主鍵值對(duì)應(yīng)的記錄刪掉就好了。
- 你刪除了一條記錄,至少要把這條記錄中的內(nèi)容都記下來(lái),這樣之后回滾時(shí)再把由這些內(nèi)容組成的記錄插入到表中就好了。
- 你修改了一條記錄,至少要把修改這條記錄前的舊值都記錄下來(lái),這樣之后回滾時(shí)再把這條記錄更新為舊值就好了。
當(dāng)事務(wù)執(zhí)行失敗或者調(diào)用了 rollback 方法時(shí),就會(huì)觸發(fā)回滾事件,利用 undo log 中記錄將數(shù)據(jù)回滾到修改之前的樣子。
更多關(guān)于 undo log 的信息,后面再單獨(dú)開(kāi)一篇文章打卡。
隔離性
定義
多個(gè)事務(wù)并發(fā)執(zhí)行的時(shí)候,事務(wù)內(nèi)部的操作與其他事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相干擾。
實(shí)現(xiàn)
隔離性可能會(huì)引入臟讀(dirty read)、不可重復(fù)讀(non-repeatable read)、幻讀(phantom read)等問(wèn)題,為了解決這些問(wèn)題就引入了“隔離級(jí)別”的概念。
SQL 標(biāo)準(zhǔn)的事務(wù)隔離級(jí)別包括:讀未提交(read uncommitted)、讀提交(read committed)、可重復(fù)讀(repeatable read)和串行化(serializable):
- 讀未提交:一個(gè)事務(wù)還沒(méi)提交時(shí),它做的變更就能被別的事務(wù)看到。
- 讀提交:一個(gè)事務(wù)提交之后,它做的變更才會(huì)被其他事務(wù)看到。
- 可重復(fù)讀: 一個(gè)事務(wù)執(zhí)行過(guò)程中看到的數(shù)據(jù),總是跟這個(gè)事務(wù)在啟動(dòng)時(shí)看到的數(shù)據(jù)是一致的。當(dāng)然在可重復(fù)讀隔離級(jí)別下,未提交變更對(duì)其他事務(wù)也是不可見(jiàn)的。
- 串行化: 顧名思義是對(duì)于同一行記錄,“寫(xiě)”會(huì)加“寫(xiě)鎖”,“讀”會(huì)加“讀鎖”。當(dāng)出現(xiàn)讀寫(xiě)鎖沖突的時(shí)候,后訪問(wèn)的事務(wù)必須等前一個(gè)事務(wù)執(zhí)行完成,才能繼續(xù)執(zhí)行。
SQL標(biāo)準(zhǔn)中規(guī)定,針對(duì)不同的隔離級(jí)別,并發(fā)事務(wù)可以發(fā)生不同嚴(yán)重程度的問(wèn)題,具體情況如下:
隔離級(jí)別臟讀不可重復(fù)讀幻讀讀未提交可能可能可能讀提交不可能可能可能可重復(fù)讀不可能不可能可能串行化不可能不可能不可能
上面就是幾種隔離級(jí)別可能出現(xiàn)的并發(fā)問(wèn)題,但是有必要說(shuō)一下,你隔離得越嚴(yán)實(shí),效率就會(huì)越低。
InnoDB 引擎是如何保證隔離性的?利用鎖和 MVCC 機(jī)制。這里簡(jiǎn)單的介紹一下 MVCC 機(jī)制,也叫多版本并發(fā)控制,在使用 READ COMMITTD、REPEATABLE READ 這兩種隔離級(jí)別的事務(wù)下,每條記錄在更新的時(shí)候都會(huì)同時(shí)記錄一條回滾操作,就會(huì)形成一個(gè)版本鏈,在執(zhí)行普通的 SELECT 操作時(shí)訪問(wèn)記錄的版本鏈的過(guò)程,這樣子可以使不同事務(wù)的讀-寫(xiě)、寫(xiě)-讀操作并發(fā)執(zhí)行,從而提升系統(tǒng)性能。
持久性
定義
事務(wù)一旦提交,它對(duì)數(shù)據(jù)庫(kù)的改變就應(yīng)該是永久性的。接下來(lái)的其他操作或故障不應(yīng)該對(duì)其有任何影響。
實(shí)現(xiàn)
要保證持久性很簡(jiǎn)單,就是每次事務(wù)提交的時(shí)候,都將數(shù)據(jù)刷磁盤(pán)上,這樣一定保證了安全性,但是要知道如果每次事務(wù)提交都將數(shù)據(jù)寫(xiě)入到磁盤(pán)的話,頻繁的 IO 操作,成本太高,數(shù)據(jù)庫(kù)的性能極低,所以這種方式不可取。
InnoDB 引擎是怎么解決的?InnoDB 引擎引入了一個(gè)中間層來(lái)解決這個(gè)持久性的問(wèn)題,我們把這個(gè)叫做 redo log(歸檔日志)。
為什么要引入 redo log?redo log 可以保證持久化又可以保證數(shù)據(jù)庫(kù)的性能,相比于直接刷盤(pán),redo log 有以下兩個(gè)優(yōu)勢(shì):
- redo log體積小,畢竟只記錄了哪一頁(yè)修改了啥,因此體積小,刷盤(pán)快。
- redo log是一直往末尾進(jìn)行追加,屬于順序IO。效率顯然比隨機(jī)IO來(lái)的快。
InnoDB 引擎是怎么做的?當(dāng)有一條記錄需要更新的時(shí)候,InnoDB 引擎就會(huì)先把記錄寫(xiě)到 redo log 里面,并更新內(nèi)存,這個(gè)時(shí)候更新就算完成了。當(dāng)數(shù)據(jù)庫(kù)宕機(jī)重啟的時(shí)候,會(huì)將 redo log 中的內(nèi)容恢復(fù)到數(shù)據(jù)庫(kù)中,再根據(jù) undo log和 binlog 內(nèi)容決定回滾數(shù)據(jù)還是提交數(shù)據(jù)。
更多 redo log,后面我打算單獨(dú)寫(xiě)一篇文章。
一致性
定義
一致性簡(jiǎn)單一點(diǎn)說(shuō)就是數(shù)據(jù)執(zhí)行前后都要處于一種合法的狀態(tài),比如身份證號(hào)不能重復(fù),性別只能是男或者女,高考的分?jǐn)?shù)只能在0~750之間,紅綠燈只有3種顏色,房?jī)r(jià)不能為負(fù)的等等, 只有符合這些約束的數(shù)據(jù)才是有效的,比如有個(gè)小孩兒跟你說(shuō)他高考考了1000分,你一聽(tīng)就知道他胡扯呢。數(shù)據(jù)庫(kù)世界只是現(xiàn)實(shí)世界的一個(gè)映射,現(xiàn)實(shí)世界中存在的約束當(dāng)然也要在數(shù)據(jù)庫(kù)世界中有所體現(xiàn)。如果數(shù)據(jù)庫(kù)中的數(shù)據(jù)全部符合現(xiàn)實(shí)世界中的約束(all defined rules),我們說(shuō)這些數(shù)據(jù)就是一致的,或者說(shuō)符合一致性的。
實(shí)現(xiàn)
要保證數(shù)據(jù)庫(kù)的數(shù)據(jù)一致性,要在以下兩個(gè)方面做努力:
- 利用數(shù)據(jù)庫(kù)的一些特性來(lái)保證部分一致性需求:比如聲明某個(gè)列為NOT NULL 來(lái)拒絕NULL值得插入等。
- 絕大部分還是需要我們程序員在編寫(xiě)業(yè)務(wù)代碼得時(shí)候來(lái)保證。
以上就是我今天要分享的內(nèi)容,希望這篇文章對(duì)你的學(xué)習(xí)或者工作有所幫助,感謝您的閱讀,如果您覺(jué)得文章不錯(cuò)歡迎點(diǎn)贊+轉(zhuǎn)發(fā),感謝。
文章出自平頭哥的技術(shù)博文
https://mp.weixin.qq.com/s?__biz=MzIyNTM4ODI0OA==&mid=2247484244&idx=1&sn=1a29e3a0d5ff9fc23de9065dee37797f&chksm=e80130e3df76b9f563bb4fb7db47dc3dc36b1a5db337600d5a3615132b017ef1b50f1f4ff576&scene=21#wechat_redirect
總結(jié)
以上是生活随笔為你收集整理的怎么实现事务_你可能知道事务的四大特性,但是不一定知道“事务的实现原理”...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 底部固定菜单_【悬浮菜单】安卓悬浮amp
- 下一篇: 安装启动gui卡住_为什么Windows