自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試題:說(shuō)說(shuō)看你對(duì)數(shù)據(jù)庫(kù)事務(wù)和 ACID 的理解?并發(fā)事務(wù)可能會(huì)產(chǎn)生哪些問(wèn)題,該如何解決?什么是快照讀和 MVCC,解決了什么問(wèn)題?

數(shù)據(jù)庫(kù)
數(shù)據(jù)庫(kù)事務(wù)是數(shù)據(jù)庫(kù)管理系統(tǒng)執(zhí)行過(guò)程中的一個(gè)邏輯單位,由一個(gè)有限的數(shù)據(jù)庫(kù)操作序列構(gòu)成。這些操作要么全部執(zhí)行成功,要么全部不執(zhí)行,是一個(gè)不可分割的工作單位。

面試題概覽:

  • 什么是數(shù)據(jù)庫(kù)的事務(wù),說(shuō)說(shuō)你對(duì)事務(wù)特性的理解;
  • 說(shuō)說(shuō)看Mysql是如何實(shí)現(xiàn)原子性的;
  • Mysql的InnoDB是如何實(shí)現(xiàn)數(shù)據(jù)持久化的;
  • 數(shù)據(jù)庫(kù)并發(fā)事務(wù)可能會(huì)出現(xiàn)什么問(wèn)題,以及該如何解決;
  • 知道什么是快照讀嗎,它是用來(lái)解決什么問(wèn)題的;

面試官:什么是數(shù)據(jù)庫(kù)的事務(wù),說(shuō)說(shuō)你對(duì)事務(wù)特性的理解?

數(shù)據(jù)庫(kù)事務(wù)是數(shù)據(jù)庫(kù)管理系統(tǒng)執(zhí)行過(guò)程中的一個(gè)邏輯單位,由一個(gè)有限的數(shù)據(jù)庫(kù)操作序列構(gòu)成。這些操作要么全部執(zhí)行成功,要么全部不執(zhí)行,是一個(gè)不可分割的工作單位。

對(duì)于事務(wù)的特性,可以從以下幾個(gè)方面來(lái)理解:

一、原子性(Atomicity)

原子性是指事務(wù)是一個(gè)不可分割的工作單位,事務(wù)中的操作要么全部完成,要么全部不完成。在數(shù)據(jù)庫(kù)操作中,如果事務(wù)中的某個(gè)操作失敗,則整個(gè)事務(wù)會(huì)回滾到事務(wù)開(kāi)始前的狀態(tài)。這種特性通過(guò)數(shù)據(jù)庫(kù)的Undo機(jī)制來(lái)實(shí)現(xiàn),即在事務(wù)執(zhí)行過(guò)程中,如果出現(xiàn)錯(cuò)誤或用戶執(zhí)行ROLLBACK語(yǔ)句,系統(tǒng)可以回滾到事務(wù)開(kāi)始前的狀態(tài)。

二、隔離性(Isolation)

隔離性是指并發(fā)執(zhí)行的事務(wù)之間相互隔離,不允許一個(gè)事務(wù)的執(zhí)行結(jié)果影響其他事務(wù)的執(zhí)行。這種特性避免了多個(gè)事務(wù)并發(fā)執(zhí)行時(shí)可能出現(xiàn)的數(shù)據(jù)不一致問(wèn)題。數(shù)據(jù)庫(kù)系統(tǒng)通常通過(guò)鎖和其他并發(fā)控制技術(shù)(如MVCC)來(lái)實(shí)現(xiàn)隔離性。表現(xiàn)形式是,當(dāng)一個(gè)事務(wù)正在對(duì)某個(gè)數(shù)據(jù)進(jìn)行操作時(shí),其他事務(wù)不能對(duì)該數(shù)據(jù)進(jìn)行并發(fā)修改,以防止數(shù)據(jù)不一致的問(wèn)題發(fā)生。

三、持久性(Durability)

持久性是指一旦事務(wù)提交,它對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變就是永久性的,即使在系統(tǒng)崩潰后,事務(wù)的修改結(jié)果也不會(huì)丟失。這種特性通過(guò)數(shù)據(jù)庫(kù)的Redo機(jī)制來(lái)實(shí)現(xiàn)。當(dāng)事務(wù)提交后,系統(tǒng)將把事務(wù)的所有操作寫(xiě)入到日志文件中,以便在系統(tǒng)恢復(fù)后通過(guò)Redo日志重新執(zhí)行這些操作,保證數(shù)據(jù)的一致性。

四、一致性(Consistency)

一致性是指事務(wù)必須將數(shù)據(jù)庫(kù)從一種一致?tīng)顟B(tài)轉(zhuǎn)換到另一種一致?tīng)顟B(tài)。這么說(shuō)有點(diǎn)抽象,我個(gè)人的具體理解是:一致性體現(xiàn)在兩點(diǎn)。

同一個(gè)表的在本次事務(wù)中有聯(lián)系的多條記錄的狀態(tài)要對(duì)的上,比如轉(zhuǎn)賬前后兩個(gè)賬戶的金額總和應(yīng)該不變(兩條同一張表的update語(yǔ)句)。

不同表在本次事務(wù)中有聯(lián)系的多條記錄的狀態(tài)要對(duì)的上,比如消費(fèi)后增加用戶積分并減少用戶金額,那么用戶的金額減少后,不能因?yàn)楣收蠈?dǎo)致用戶積分沒(méi)增加(兩條不同表的update語(yǔ)句)。

上述四個(gè)特點(diǎn)中,一致性是事務(wù)的最終目的。只要其他三個(gè)特性都滿足了,那么一致性自然而然也就會(huì)滿足,也就是說(shuō)原子性,隔離性和持久性是需要作出的努力,一致性是我們想要的結(jié)果。

面試官:原子性——說(shuō)說(shuō)看Mysql是如何通過(guò)undo日志實(shí)現(xiàn)原子性?

首先是MySQL如何通過(guò)undo日志實(shí)現(xiàn)原子性的詳細(xì)解釋?zhuān)?/p>

一、undo日志的作用

undo日志,也被稱(chēng)為回滾日志,是MySQL中用于記錄事務(wù)在執(zhí)行過(guò)程中對(duì)數(shù)據(jù)的修改前的狀態(tài)(即舊值)的一種日志。當(dāng)事務(wù)需要回滾時(shí),MySQL可以利用undo日志將數(shù)據(jù)恢復(fù)到事務(wù)開(kāi)始前的狀態(tài),從而保證事務(wù)的原子性。

undo日志分為3類(lèi):

  • insert操作對(duì)應(yīng)的undo日志
  • delete操作對(duì)應(yīng)的日志
  • update操作對(duì)應(yīng)的undo日志

下面是undo日志的具體結(jié)構(gòu),其他的不用關(guān)注,重點(diǎn)關(guān)注圖中倒數(shù)第二格的 <len, value>,里面包含增刪改操作前的具體字段和值,數(shù)據(jù)庫(kù)回滾就是通過(guò)這些字段和值來(lái)進(jìn)行的。

二、實(shí)現(xiàn)原子性的過(guò)程

(1) 事務(wù)開(kāi)始:

  • 當(dāng)一個(gè)事務(wù)開(kāi)始時(shí),MySQL會(huì)監(jiān)控該事務(wù)對(duì)數(shù)據(jù)庫(kù)的所有修改操作。

(2) 記錄undo日志:

  • 在事務(wù)執(zhí)行過(guò)程中,每當(dāng)對(duì)數(shù)據(jù)庫(kù)進(jìn)行寫(xiě)操作(如INSERT、UPDATE、DELETE)時(shí),MySQL會(huì)將修改前的數(shù)據(jù)狀態(tài)(舊值)保存在undo日志中。
  • undo日志是邏輯日志,它記錄的是修改前的數(shù)據(jù)狀態(tài),而不是物理存儲(chǔ)的修改。

(3) 事務(wù)提交或回滾:

  • 如果事務(wù)成功執(zhí)行并提交,那么這些修改將持久化到數(shù)據(jù)庫(kù)中,而undo日志則會(huì)在一定時(shí)間后被清理(通常是在事務(wù)提交后,且確保沒(méi)有其他并發(fā)事務(wù)需要回滾到該事務(wù)之前的狀態(tài)時(shí))。
  • 如果事務(wù)在執(zhí)行過(guò)程中遇到錯(cuò)誤或用戶顯式要求回滾,那么MySQL會(huì)利用undo日志中的信息,將數(shù)據(jù)庫(kù)恢復(fù)到事務(wù)開(kāi)始前的狀態(tài)。

三、undo日志的具體實(shí)現(xiàn)

1.undo日志的存儲(chǔ):

undo日志被存儲(chǔ)在InnoDB存儲(chǔ)引擎的專(zhuān)用頁(yè)面中,這些頁(yè)面被稱(chēng)為undo頁(yè)面。

undo頁(yè)分為兩種:insert類(lèi)型的undo日志(里面只放insert類(lèi)型的undo日志) 和 update類(lèi)型的undo日志(放update和delete類(lèi)型的undo日志)。

undo頁(yè)面以鏈表的形式組織,每個(gè)undo頁(yè)面都包含了多條undo日志,Innodb會(huì)為每一個(gè)事務(wù)一條或兩條undo鏈表(如果該事務(wù)同時(shí)包含增刪改操作就會(huì)生成兩條undo鏈表)。

之所以要將同一個(gè)事務(wù)產(chǎn)生的undo日志組織在同一個(gè)鏈表而非所有事務(wù)的undo日志組織成一個(gè)鏈表也是為了回滾時(shí)可以按事務(wù)的維度找到只和本事務(wù)相關(guān)的undo日志進(jìn)行回滾。

兩種不同類(lèi)型的undo日志頁(yè)分別用 insert undo 鏈表 和 update undo 鏈表管理。

把 undo 日志分成 2 個(gè)大類(lèi)是因?yàn)閕nsert類(lèi)型的 undo 日志在事務(wù)提交后可以直接刪除,而其他類(lèi)型的 undo 日志還需要為 MVCC(多版本并發(fā)控制)服務(wù),不能在事務(wù)提交后馬上刪除。

2.回滾操作:

當(dāng)事務(wù)需要回滾時(shí),MySQL會(huì)沿著undo日志鏈表,按照與事務(wù)執(zhí)行相反的順序,逐條應(yīng)用undo日志中的信息,將數(shù)據(jù)恢復(fù)到事務(wù)開(kāi)始前的狀態(tài)。

  • 對(duì)于INSERT操作,undo日志記錄的是“刪除”操作,即如果事務(wù)回滾,需要撤銷(xiāo)插入的數(shù)據(jù)。
  • 對(duì)于DELETE操作,undo日志記錄的是“插入”操作,即如果事務(wù)回滾,需要恢復(fù)被刪除的數(shù)據(jù)。
  • 對(duì)于UPDATE操作,undo日志記錄的是修改前的舊值,即如果事務(wù)回滾,需要將數(shù)據(jù)更新回舊值。

面試官:持久性——Mysql的InnoDB是如何實(shí)現(xiàn)數(shù)據(jù)持久化的?

說(shuō)到數(shù)據(jù)庫(kù)持久化就繞不開(kāi) WAL 機(jī)制 和 redo日志。

一、WAL和redo log的基本概念

WAL是一種數(shù)據(jù)安全寫(xiě)入機(jī)制,其核心思想是在事務(wù)進(jìn)行修改之前,先將修改操作記錄到日志中,然后再將修改應(yīng)用到數(shù)據(jù)庫(kù)中。這樣做的好處是,即使系統(tǒng)崩潰或斷電,也可以通過(guò)日志來(lái)恢復(fù)數(shù)據(jù),保證數(shù)據(jù)的持久性和一致性。

redo日志是InnoDB存儲(chǔ)引擎獨(dú)有的物理日志,記錄了數(shù)據(jù)操作的細(xì)節(jié),包括事務(wù)開(kāi)始和結(jié)束的標(biāo)志、修改的數(shù)據(jù)頁(yè)和對(duì)應(yīng)的操作等。它主要用于故障恢復(fù),當(dāng)數(shù)據(jù)庫(kù)發(fā)生異常關(guān)閉或崩潰時(shí),InnoDB可以通過(guò)redo日志來(lái)恢復(fù)數(shù)據(jù)。

redo日志以固定大小的多個(gè)文件(如ib_logfile0、ib_logfile1)形成的文件組的形式存在,是一個(gè)可覆蓋的循環(huán)日志。InnoDB 的 redo log 是固定大小的,比如可以配置為一組 4 個(gè)文件,每個(gè)文件的大小是 1GB,那么這塊“粉板”總共就可以記錄 4GB 的操作。從頭開(kāi)始寫(xiě),寫(xiě)到末尾就又回到開(kāi)頭循環(huán)寫(xiě),如下面這個(gè)圖所示。

write pos 是當(dāng)前記錄的位置,一邊寫(xiě)一邊后移,寫(xiě)到第 3 號(hào)文件末尾后就回到 0 號(hào)文件開(kāi)頭。checkpoint 標(biāo)記了日志中已經(jīng)刷盤(pán)成功的數(shù)據(jù)所對(duì)應(yīng)的redo日志數(shù)據(jù)。

write pos 和 checkpoint 之間的是redo日志上可被新的事務(wù)的增刪改操作所覆蓋的部分,可以用來(lái)記錄新的操作。如果 write pos 追上 checkpoint,表示redo日志滿了,這時(shí)候不能再執(zhí)行新的更新,得停下來(lái)將Buffer Pool中的臟頁(yè)刷盤(pán),把 checkpoint 推進(jìn)一下才能繼續(xù)寫(xiě)redo日志。

有了 redo log,InnoDB 就可以保證即使數(shù)據(jù)庫(kù)發(fā)生異常重啟,之前提交的記錄都不會(huì)丟失,這個(gè)能力稱(chēng)為 crash-safe。

下圖是一條簡(jiǎn)單redo日志的數(shù)據(jù)結(jié)構(gòu):

其中 space ID 表示本修改所對(duì)應(yīng)的數(shù)據(jù)頁(yè)所在的表空間,page number是所修改的頁(yè)號(hào),offer是所修改的數(shù)據(jù)在頁(yè)中的偏移量。通過(guò)這3個(gè)信息,就可以在故障恢復(fù)時(shí)找到要恢復(fù)的數(shù)據(jù)頁(yè)和數(shù)據(jù)頁(yè)中的具體位置。

二、redo log寫(xiě)入的具體過(guò)程

(1) 事務(wù)開(kāi)始:

當(dāng)一個(gè)事務(wù)開(kāi)始時(shí),MySQL會(huì)為該事務(wù)分配一個(gè)唯一的事務(wù)ID,并將該事務(wù)的相關(guān)信息存儲(chǔ)在內(nèi)存中的事務(wù)控制塊(Transaction Control Block, TCB)中。

(2) 修改操作記錄到redo log buffer:

在事務(wù)執(zhí)行過(guò)程中,所有的修改操作(如插入、更新、刪除等)都會(huì)被寫(xiě)入redo log緩沖區(qū)(redo log buffer)。redo log buffer是一個(gè)內(nèi)存緩沖區(qū),用于暫存待寫(xiě)入redo log的修改操作。

(3) 事務(wù)提交和redo log刷盤(pán):

當(dāng)事務(wù)提交時(shí),MySQL會(huì)將該事務(wù)的所有修改操作按照順序?qū)懭雛edo log文件中。這個(gè)過(guò)程稱(chēng)為redo log的刷新(flush)。

需要注意的是,在事務(wù)提交之前,MySQL并不會(huì)立即將redo log buffer中的修改操作持久化到磁盤(pán)上的redo log文件中。而是會(huì)等待一個(gè)合適的時(shí)機(jī)來(lái)進(jìn)行持久化操作?;趇nnodb_flush_log_at_trx_commit配置參數(shù)的刷盤(pán)策略如下。

innodb_flush_log_at_trx_commit:
  • 值=1:每次事務(wù)提交時(shí)都會(huì)將日志刷新到磁盤(pán),確保了最高的持久性(默認(rèn)值)。
  • 值=2:日志寫(xiě)入到操作系統(tǒng)的緩存(log buffer)并每秒刷寫(xiě)到磁盤(pán)(可能會(huì)存在少量數(shù)據(jù)丟失的風(fēng)險(xiǎn),但提高性能)。
  • 值=0:日志寫(xiě)入到操作系統(tǒng)的緩存(log buffer),并每次檢查點(diǎn)時(shí)刷寫(xiě)到磁盤(pán)(可能存在更多的數(shù)據(jù)丟失風(fēng)險(xiǎn))。

三、恢復(fù)數(shù)據(jù)的詳細(xì)過(guò)程

(1) 啟動(dòng)InnoDB:當(dāng)MySQL服務(wù)重啟時(shí),InnoDB存儲(chǔ)引擎會(huì)開(kāi)始啟動(dòng)。

(2) 定位checkpoint:InnoDB會(huì)通過(guò)redo日志找到最近一次checkpoint的位置。checkpoint信息保存在日志文件的開(kāi)始部分,包括checkpoint號(hào)、checkpoint lsn(記錄了產(chǎn)生該checkpoint時(shí)flush的LSN,確保在該LSN前面的數(shù)據(jù)頁(yè)都已經(jīng)落盤(pán),不再需要通過(guò)redo log進(jìn)行恢復(fù))和checkpoint offset(記錄了該checkpoint產(chǎn)生時(shí),redo log在ib_logfile中的偏移量)。

(3) 獲取并解析redo日志:

從checkpoint相對(duì)應(yīng)的位置開(kāi)始,InnoDB會(huì)獲取需要重做的日志。

接著,InnoDB會(huì)解析獲取的日志,并將其保存到一個(gè)哈希表中。哈希表以(space,offset)為鍵,存儲(chǔ)了redo日志的信息。

(4) 數(shù)據(jù)恢復(fù):

InnoDB會(huì)遍歷哈希表中的redo日志信息。

對(duì)于每條redo日志,InnoDB會(huì)根據(jù)(space ID,page number,offset)讀取指定頁(yè)面,并進(jìn)行日志覆蓋,即根據(jù)redo日志中的記錄來(lái)恢復(fù)數(shù)據(jù)頁(yè)的內(nèi)容。

面試官:數(shù)據(jù)庫(kù)并發(fā)事務(wù)可能會(huì)出現(xiàn)什么問(wèn)題,以及該如何解決?

一、數(shù)據(jù)一致性問(wèn)題

1.臟讀

一個(gè)事務(wù)讀取了另一個(gè)事務(wù)未提交的數(shù)據(jù),這些數(shù)據(jù)可能會(huì)被回滾,從而導(dǎo)致讀取到無(wú)效數(shù)據(jù)。

以下是一個(gè)具體的臟讀示例:

事務(wù)A首先執(zhí)行了一個(gè)select操作,從account表中讀取了id=1的賬戶的money值,此時(shí)得到的mnotallow=0。

接著,事務(wù)A嘗試執(zhí)行一個(gè)update操作,將id=1的賬戶的money值設(shè)置為2000。另一個(gè)事務(wù)(事務(wù)B)修改了該賬戶的money值,并且這個(gè)修改還未提交。

如果事務(wù)A最終不提交其修改,那么事務(wù)B讀取到的mnotallow=2000就是一個(gè)“臟讀”,即讀取到了其他事務(wù)還未提交的數(shù)據(jù)。

事務(wù)B基于這個(gè)“臟讀”的數(shù)據(jù)進(jìn)行業(yè)務(wù)處理可能會(huì)導(dǎo)致問(wèn)題,例如修改了其他表里的數(shù)據(jù),最終數(shù)據(jù)不一致。

為了避免臟讀,數(shù)據(jù)庫(kù)系統(tǒng)通常實(shí)施更高的事務(wù)隔離級(jí)別,如READ COMMITTED或更高,以確保事務(wù)只能讀取到已提交的數(shù)據(jù)。

2.不可重復(fù)讀

一個(gè)事務(wù)在兩次讀取同一數(shù)據(jù)時(shí),因其他事務(wù)的提交導(dǎo)致本事務(wù)數(shù)據(jù)發(fā)生了變化,從而兩次讀取無(wú)法獲得一致的結(jié)果。不可重復(fù)讀會(huì)在事務(wù)需要基于多次讀取結(jié)果進(jìn)行復(fù)雜計(jì)算時(shí)產(chǎn)生影響。

以下是一個(gè)不可重復(fù)讀示例:

為了避免不可重復(fù)讀,數(shù)據(jù)庫(kù)系統(tǒng)需要實(shí)施適當(dāng)?shù)氖聞?wù)隔離級(jí)別(如READ COMMITTED或更高)或使用其他并發(fā)控制機(jī)制來(lái)確保事務(wù)在讀取數(shù)據(jù)時(shí)不會(huì)受到其他事務(wù)修改數(shù)據(jù)的影響。

在READ COMMITTED隔離級(jí)別下,事務(wù)只能讀取到其他事務(wù)已經(jīng)提交的修改,從而避免了臟讀和不可重復(fù)讀(但幻讀仍然可能發(fā)生)。而在更高的隔離級(jí)別(如REPEATABLE READ或SERIALIZABLE)下,數(shù)據(jù)庫(kù)系統(tǒng)會(huì)進(jìn)一步限制并發(fā)操作,以減少或消除幻讀現(xiàn)象,但會(huì)嚴(yán)重影響并發(fā)性能。

3.幻讀

一個(gè)事務(wù)(通過(guò)條件)讀取多條記錄后,因其他事務(wù)的插入或刪除,導(dǎo)致再次讀取時(shí)獲得的記錄集發(fā)生變化?;米x問(wèn)題通常發(fā)生在插入或刪除操作頻繁的場(chǎng)景中。

以下是一個(gè)幻讀的具體示例:

再舉一個(gè)關(guān)于幻讀的例子加強(qiáng)一下大家對(duì)幻讀的理解:

假設(shè)有一個(gè)銀行系統(tǒng),它有一個(gè)賬戶表(accounts),用于記錄客戶的賬戶余額和其他相關(guān)信息?,F(xiàn)在,有兩個(gè)事務(wù)T1和T2同時(shí)運(yùn)行,并且它們都對(duì)滿足某個(gè)條件的賬戶集合進(jìn)行操作。

(1) 事務(wù)T1:

  • 開(kāi)始事務(wù)。
  • 事務(wù)T1的目標(biāo)是查詢(xún)并處理所有余額大于500元的賬戶。它首先執(zhí)行一個(gè)查詢(xún)操作,找出所有余額大于500元的賬戶,并假設(shè)找到了賬戶A、B和C(這些賬戶的余額都大于500元)。
  • 此時(shí),事務(wù)T1尚未提交,也沒(méi)有對(duì)查詢(xún)結(jié)果進(jìn)行任何處理。

(2) 事務(wù)T2:

  • 同時(shí)開(kāi)始事務(wù)。
  • 事務(wù)T2的目標(biāo)是向系統(tǒng)中添加一個(gè)新的賬戶D,并且這個(gè)新賬戶的余額設(shè)置為600元。它執(zhí)行一個(gè)插入操作,將新賬戶D添加到賬戶表中,并提交事務(wù)。

(3) 事務(wù)T1(繼續(xù)):

  • 在事務(wù)T1中,經(jīng)過(guò)一段時(shí)間后(在事務(wù)T2提交之后),事務(wù)T1決定對(duì)之前查詢(xún)到的賬戶集合(賬戶A、B和C)進(jìn)行處理。但在處理之前,它再次執(zhí)行了一個(gè)相同的查詢(xún)操作,以確認(rèn)要處理的賬戶集合。
  • 然而,這次查詢(xún)的結(jié)果中除了賬戶A、B和C之外,還多了一個(gè)新的賬戶D(因?yàn)槭聞?wù)T2已經(jīng)添加了新賬戶D,并且D的余額大于500元,滿足查詢(xún)條件)。
  • 這導(dǎo)致事務(wù)T1在處理賬戶集合時(shí)遇到了一個(gè)“幻影”賬戶D,這個(gè)賬戶在事務(wù)T1的第一次查詢(xún)中并不存在,但在第二次查詢(xún)中卻出現(xiàn)了。

(4) 結(jié)果:事務(wù)T1在處理賬戶集合時(shí),由于幻讀現(xiàn)象,它必須處理一個(gè)額外的賬戶D,這可能導(dǎo)致一些意外的行為或錯(cuò)誤。例如,如果事務(wù)T1的目標(biāo)是向所有余額大于500元的老賬戶發(fā)送一條通知,那么由于幻讀現(xiàn)象,新賬戶D也會(huì)收到這條通知。

為了避免幻讀,數(shù)據(jù)庫(kù)系統(tǒng)需要實(shí)施更高的事務(wù)隔離級(jí)別(如SERIALIZABLE)或使用其他并發(fā)控制機(jī)制(如鎖機(jī)制或MVCC)來(lái)確保事務(wù)在讀取數(shù)據(jù)時(shí)不會(huì)受到其他事務(wù)插入或刪除數(shù)據(jù)的影響。

可能得面試官追問(wèn):不可重復(fù)度和幻讀看上去形式上都是兩次讀取的結(jié)果不同,那么不可重復(fù)讀和幻讀的區(qū)別是什么?

(1) 發(fā)生場(chǎng)景不同:

  • 不可重復(fù)讀通常發(fā)生在數(shù)據(jù)集合中具體數(shù)據(jù)項(xiàng)的值被其他事務(wù)修改后。
  • 幻讀通常發(fā)生在查詢(xún)結(jié)果集合因其他事務(wù)的插入操作而發(fā)生變化時(shí)。

(2) 關(guān)注點(diǎn)不同:

  • 不可重復(fù)讀關(guān)注的是數(shù)據(jù)項(xiàng)值的變化。
  • 幻讀關(guān)注的是查詢(xún)結(jié)果集合中記錄數(shù)量或內(nèi)容的變化。

并發(fā)事務(wù)除了出現(xiàn)數(shù)據(jù)一致性問(wèn)題之外,還可能存在其他問(wèn)題(如死鎖和性能下降等)。

二、死鎖

死鎖是指兩個(gè)或多個(gè)事務(wù)在執(zhí)行過(guò)程中,因?yàn)橄嗷コ钟袑?duì)方所需要的資源而陷入無(wú)限等待的狀態(tài)。死鎖會(huì)導(dǎo)致系統(tǒng)資源無(wú)法有效利用,嚴(yán)重時(shí)可能會(huì)使系統(tǒng)陷入癱瘓。常見(jiàn)的死鎖場(chǎng)景包括兩個(gè)事務(wù)互相等待對(duì)方釋放鎖,以及多個(gè)事務(wù)循環(huán)等待。

三、性能下降

并發(fā)事務(wù)增多會(huì)增加系統(tǒng)的CPU、內(nèi)存和I/O負(fù)載,影響整體性能。具體表現(xiàn)為:

  • 鎖競(jìng)爭(zhēng):多個(gè)事務(wù)同時(shí)請(qǐng)求同一個(gè)資源,導(dǎo)致鎖競(jìng)爭(zhēng),進(jìn)而引發(fā)事務(wù)等待和超時(shí)。
  • 資源消耗:并發(fā)事務(wù)會(huì)占用大量系統(tǒng)資源,如CPU、內(nèi)存和磁盤(pán)I/O等。

說(shuō)到事務(wù)并發(fā)就不得不先說(shuō)數(shù)據(jù)庫(kù)的隔離級(jí)別。事務(wù)的隔離級(jí)別是數(shù)據(jù)庫(kù)中用于控制并發(fā)事務(wù)間相互影響的機(jī)制。

以下是關(guān)于事務(wù)隔離級(jí)別的詳細(xì)解釋以及選擇建議:

事務(wù)隔離級(jí)別的類(lèi)型

(1) 讀未提交(READ UNCOMMITTED):

  • 允許事務(wù)讀取其他事務(wù)尚未提交的數(shù)據(jù)。
  • 可能導(dǎo)致臟讀,即讀取到其他事務(wù)未提交的已update的但之后可能回滾的無(wú)效數(shù)據(jù)。
  • 并發(fā)性能較高,但數(shù)據(jù)一致性較差。

(2) 讀提交(READ COMMITTED):

  • 事務(wù)只能讀取已經(jīng)提交的數(shù)據(jù)。
  • 避免了臟讀,但仍可能產(chǎn)生不可重復(fù)讀和幻讀。
  • 適用于大多數(shù)在線事務(wù)處理(OLTP)應(yīng)用,能在一定程度上保證數(shù)據(jù)一致性。

(3) 可重復(fù)讀(REPEATABLE READ):

  • 在同一事務(wù)中多次讀取同一數(shù)據(jù)會(huì)得到相同的結(jié)果,即使其他事務(wù)已經(jīng)提交了修改。
  • 解決了不可重復(fù)讀問(wèn)題,但仍可能產(chǎn)生幻讀(即新插入的數(shù)據(jù)對(duì)于當(dāng)前事務(wù)不可見(jiàn),但可能導(dǎo)致后續(xù)插入沖突)。
  • 適用于需要保證數(shù)據(jù)一致性的復(fù)雜業(yè)務(wù)邏輯。

(4) 序列化(SERIALIZABLE):

  • 提供了最高的事務(wù)隔離級(jí)別,事務(wù)之間完全隔離,互不干擾。
  • 避免了臟讀、不可重復(fù)讀和幻讀等所有并發(fā)問(wèn)題。
  • 但由于事務(wù)需要串行執(zhí)行,性能損失較大,適用于對(duì)數(shù)據(jù)一致性要求極高的關(guān)鍵業(yè)務(wù)。

面試官:知道什么是快照讀嗎,它是用來(lái)解決什么問(wèn)題的?

(下面的內(nèi)容可能有點(diǎn)長(zhǎng),希望大家能耐心看完,畢竟面試加分的本質(zhì)就是答出面試官所問(wèn)的這個(gè)問(wèn)題相關(guān)的但沒(méi)有問(wèn)出來(lái)的點(diǎn))。

快照讀(Snapshot Read)是數(shù)據(jù)庫(kù)事務(wù)處理中的一種讀取數(shù)據(jù)的方式,它確保事務(wù)在讀取數(shù)據(jù)時(shí)看到的是數(shù)據(jù)在某個(gè)時(shí)間點(diǎn)(即事務(wù)開(kāi)始時(shí))的狀態(tài),就像拍攝了一張數(shù)據(jù)在那個(gè)時(shí)間點(diǎn)的“快照”一樣。這種讀取方式不會(huì)受到其他并發(fā)事務(wù)的影響,即使其他事務(wù)在讀取過(guò)程中對(duì)數(shù)據(jù)進(jìn)行了修改,快照讀仍然能夠讀取到事務(wù)開(kāi)始時(shí)的數(shù)據(jù)版本。

快照讀的主要特點(diǎn)是:

  • 一致性:快照讀保證了事務(wù)在讀取數(shù)據(jù)時(shí)的一致性,因?yàn)樽x取的是事務(wù)開(kāi)始時(shí)的數(shù)據(jù)快照,所以不會(huì)受到其他并發(fā)事務(wù)的干擾。
  • 并發(fā)性:由于快照讀不需要對(duì)數(shù)據(jù)加鎖,因此可以提高數(shù)據(jù)庫(kù)的并發(fā)性能。多個(gè)事務(wù)可以同時(shí)進(jìn)行快照讀,而不會(huì)相互阻塞。
  • 隔離性:快照讀提供了一種事務(wù)隔離的機(jī)制,使得每個(gè)事務(wù)都像在獨(dú)立的環(huán)境中運(yùn)行一樣,不會(huì)受到其他事務(wù)的影響。

在MySQL等數(shù)據(jù)庫(kù)系統(tǒng)中,快照讀通常是通過(guò)多版本并發(fā)控制(MVCC,Multi-Version Concurrency Control)來(lái)實(shí)現(xiàn)的。

MVCC是數(shù)據(jù)庫(kù)管理系統(tǒng)中用于實(shí)現(xiàn)并發(fā)控制的一種方法。通過(guò)維護(hù)數(shù)據(jù)的多個(gè)版本來(lái)實(shí)現(xiàn)并發(fā)控制。

在MVCC中,每個(gè)數(shù)據(jù)項(xiàng)都有多個(gè)版本,每個(gè)版本都記錄了一個(gè)時(shí)間點(diǎn)或事務(wù)ID,表示該版本被創(chuàng)建或修改的時(shí)間。當(dāng)一個(gè)事務(wù)讀取數(shù)據(jù)時(shí),它會(huì)讀取一個(gè)特定時(shí)間點(diǎn)的快照,這個(gè)快照包含了在該時(shí)間點(diǎn)之前提交的所有事務(wù)的結(jié)果。通過(guò)這種方式,事務(wù)可以看到一個(gè)一致的視圖,而不受其他事務(wù)的影響。

具體來(lái)說(shuō),MVCC的實(shí)現(xiàn)通常依賴(lài)于以下幾個(gè)關(guān)鍵組件:

一、Undo Log

定義:Undo Log是數(shù)據(jù)庫(kù)中用于記錄數(shù)據(jù)修改歷史的日志。當(dāng)事務(wù)進(jìn)行更新或刪除操作時(shí),數(shù)據(jù)庫(kù)會(huì)生成相應(yīng)的Undo Log,以便在需要時(shí)能夠回滾到之前的版本。

在MVCC中,Undo Log不僅用于事務(wù)回滾,還用于維護(hù)版本鏈,一條undo日志會(huì)作為版本鏈中的一個(gè)節(jié)點(diǎn),節(jié)點(diǎn)之間通過(guò)undo日志的回滾指針連接。

當(dāng)事務(wù)進(jìn)行更新或刪除操作時(shí),數(shù)據(jù)庫(kù)會(huì)生成一條undo日志作為新的數(shù)據(jù)版本,并通過(guò)undo日志的回滾指針將新舊版本(舊的undo日志)連接起來(lái),形成版本鏈。

二、版本鏈

定義:版本鏈?zhǔn)侵该總€(gè)數(shù)據(jù)項(xiàng)都維護(hù)一個(gè)記錄其修改歷史的鏈表。鏈表中的每個(gè)節(jié)點(diǎn)代表數(shù)據(jù)項(xiàng)的一個(gè)版本,這里的“一個(gè)版本”就是一條undo日志,包括歷史記錄的數(shù)據(jù)內(nèi)容、修改時(shí)間戳或事務(wù)ID等信息。

實(shí)現(xiàn):在數(shù)據(jù)庫(kù)中,每個(gè)數(shù)據(jù)行都會(huì)有一個(gè)隱藏的回滾指針(roll_pointer)字段,該字段指向該行的上一個(gè)版本(如果存在的話)。這樣,通過(guò)回滾指針,可以將各個(gè)版本連接起來(lái),形成一個(gè)版本鏈。

下圖呈現(xiàn)了兩個(gè)事務(wù)對(duì)數(shù)據(jù)表修改過(guò)程中生成版本鏈的過(guò)程。

假設(shè)一開(kāi)始hero.name = "劉備"。那么版本鏈如下:

三、讀視圖(Read View)

定義:讀視圖是數(shù)據(jù)庫(kù)在特定時(shí)刻為某個(gè)事務(wù)創(chuàng)建的一個(gè)快照,該快照包含了在該時(shí)刻所有未提交事務(wù)的信息。

實(shí)現(xiàn):讀視圖通常包含以下關(guān)鍵信息:

  • 當(dāng)前活躍的事務(wù)編號(hào)集合(m_ids):記錄了當(dāng)前所有未提交事務(wù)的事務(wù)ID。
  • 最小活躍事務(wù)編號(hào)(min_trx_id):當(dāng)前活躍事務(wù)中的最小事務(wù)ID。
  • 最大事務(wù)編號(hào)+1(max_trx_id):預(yù)分配的事務(wù)編號(hào),用于判斷新事務(wù)是否在當(dāng)前讀視圖的范圍內(nèi)。
  • 讀視圖創(chuàng)建者的事務(wù)編號(hào)(creator_trx_id):記錄了創(chuàng)建該讀視圖的事務(wù)ID。

作用:讀視圖用于判斷哪些數(shù)據(jù)版本對(duì)當(dāng)前事務(wù)是可見(jiàn)的。具體來(lái)說(shuō),當(dāng)一個(gè)事務(wù)讀取數(shù)據(jù)時(shí),它會(huì)根據(jù)讀視圖中的信息,在版本鏈中查找滿足條件的版本。

四、MVCC的讀操作實(shí)現(xiàn)

當(dāng)事務(wù)進(jìn)行讀操作時(shí),數(shù)據(jù)庫(kù)會(huì)根據(jù)讀視圖和版本鏈來(lái)判斷應(yīng)該讀取哪個(gè)版本的數(shù)據(jù)。具體來(lái)說(shuō),數(shù)據(jù)庫(kù)會(huì)按照以下步驟進(jìn)行讀操作:

  • 從版本鏈的最新版本開(kāi)始,逐個(gè)比較數(shù)據(jù)版本的事務(wù)ID和讀視圖中的信息。
  • 如果數(shù)據(jù)版本的事務(wù)ID小于讀視圖中的最小活躍事務(wù)編號(hào)(min_trx_id),則說(shuō)明該版本已經(jīng)提交,對(duì)當(dāng)前事務(wù)可見(jiàn),可以直接讀取。
  • 如果數(shù)據(jù)版本的事務(wù)ID大于或等于讀視圖中的最大事務(wù)編號(hào)(max_trx_id),則說(shuō)明該版本是在當(dāng)前事務(wù)之后生成的,對(duì)當(dāng)前事務(wù)不可見(jiàn),繼續(xù)查找下一個(gè)版本。
  • 如果數(shù)據(jù)版本的事務(wù)ID在最小活躍事務(wù)編號(hào)和最大事務(wù)編號(hào)之間,則需要進(jìn)一步檢查該事務(wù)ID是否在當(dāng)前活躍事務(wù)集合(m_ids)中。如果在集合中,則說(shuō)明該事務(wù)尚未提交,對(duì)當(dāng)前事務(wù)不可見(jiàn);如果不在集合中,則說(shuō)明該事務(wù)已經(jīng)提交,對(duì)當(dāng)前事務(wù)可見(jiàn)。
  • 重復(fù)以上步驟,直到找到對(duì)當(dāng)前事務(wù)可見(jiàn)的數(shù)據(jù)版本或遍歷完整個(gè)版本鏈為止。

五、MVCC解決的問(wèn)題

MVCC主要解決了數(shù)據(jù)庫(kù)在高并發(fā)環(huán)境下的讀寫(xiě)沖突問(wèn)題,以及數(shù)據(jù)一致性問(wèn)題。具體來(lái)說(shuō),它解決了以下幾個(gè)方面的問(wèn)題:

  • 臟讀:在沒(méi)有MVCC的情況下,一個(gè)事務(wù)可能讀取到另一個(gè)未提交事務(wù)修改過(guò)的數(shù)據(jù)。如果后者回滾,那么前者讀取的就是“臟”數(shù)據(jù)。MVCC通過(guò)確保事務(wù)只能讀取到已提交的數(shù)據(jù)版本,從而避免了臟讀問(wèn)題。
  • 不可重復(fù)讀:在數(shù)據(jù)庫(kù)操作期間,如果沒(méi)有適當(dāng)?shù)母綦x機(jī)制,一個(gè)事務(wù)多次讀取同一數(shù)據(jù)可能會(huì)得到不同的結(jié)果。這是因?yàn)槠渌聞?wù)可能在此期間修改了這些數(shù)據(jù)。MVCC通過(guò)為每個(gè)事務(wù)提供一個(gè)一致的數(shù)據(jù)快照,從而解決了不可重復(fù)讀問(wèn)題。
  • 幻讀:幻讀是指在同一個(gè)事務(wù)中,執(zhí)行相同的查詢(xún)語(yǔ)句,但第二次查詢(xún)卻返回了第一次查詢(xún)中沒(méi)有的新記錄。MVCC可以在一定程度上減少幻讀的發(fā)生,尤其是在讀取時(shí)沒(méi)有主動(dòng)加鎖的情況下。但需要注意的是,MVCC并不能完全解決幻讀問(wèn)題,在某些情況下仍然需要使用其他機(jī)制(如間隙鎖)來(lái)防止幻讀。
  • 提高并發(fā)性能:由于讀操作不需要等待寫(xiě)操作完成,寫(xiě)操作也不會(huì)阻止其他事務(wù)進(jìn)行讀取,因此MVCC可以顯著提高系統(tǒng)的并發(fā)處理能力。這對(duì)于讀多寫(xiě)少的場(chǎng)景尤為有效。
  • 減少鎖的使用:雖然MVCC本身也是一種形式的鎖定機(jī)制(通過(guò)版本鏈和讀視圖實(shí)現(xiàn)),但它減少了傳統(tǒng)意義上的行鎖或表鎖的需求。這有助于減少鎖競(jìng)爭(zhēng)和鎖開(kāi)銷(xiāo),從而提高系統(tǒng)的性能。

(面試官可能得追問(wèn):MVCC的缺點(diǎn))

維護(hù)MVCC并不是沒(méi)有成本的,下面是MVCC所帶來(lái)的問(wèn)題:

  • 存儲(chǔ)開(kāi)銷(xiāo)增加:為了支持MVCC,數(shù)據(jù)庫(kù)需要存儲(chǔ)數(shù)據(jù)的多個(gè)版本。這會(huì)增加存儲(chǔ)空間的使用,特別是在頻繁更新數(shù)據(jù)的場(chǎng)景下。舊版本的數(shù)據(jù)可能會(huì)迅速積累,導(dǎo)致存儲(chǔ)空間的快速增長(zhǎng)。
  • 寫(xiě)性能下降:在MVCC機(jī)制下,每次更新操作都需要?jiǎng)?chuàng)建新的數(shù)據(jù)版本,并將舊版本的數(shù)據(jù)標(biāo)記為無(wú)效或刪除。這些額外的操作會(huì)增加寫(xiě)操作的復(fù)雜性和時(shí)間開(kāi)銷(xiāo),從而導(dǎo)致寫(xiě)性能下降。
  • 清理過(guò)期版本的開(kāi)銷(xiāo):隨著時(shí)間的推移,數(shù)據(jù)庫(kù)中會(huì)積累大量的過(guò)期版本數(shù)據(jù)。這些過(guò)期版本數(shù)據(jù)不再被任何事務(wù)所需,因此需要定期清理。然而,清理過(guò)期版本數(shù)據(jù)是一個(gè)復(fù)雜的任務(wù),需要數(shù)據(jù)庫(kù)系統(tǒng)掃描整個(gè)數(shù)據(jù)庫(kù)來(lái)識(shí)別并刪除無(wú)效的數(shù)據(jù)版本。這個(gè)過(guò)程可能會(huì)消耗大量的計(jì)算資源和時(shí)間。
責(zé)任編輯:趙寧寧 來(lái)源: 程序員阿沛
相關(guān)推薦

2024-11-19 18:27:50

2021-07-13 07:52:03

ReactHooks組件

2021-07-29 07:55:20

React Fiber架構(gòu)引擎

2024-11-19 08:00:00

2023-05-31 07:32:37

2024-11-19 12:00:00

緩存擊穿緩存緩存穿透

2010-05-13 09:59:50

MySQL數(shù)據(jù)庫(kù)

2024-01-10 09:44:11

MySQL死鎖

2025-04-30 10:10:00

在 C++C++11Lambda

2022-03-30 07:28:24

MySQL數(shù)據(jù)庫(kù)ACID

2024-12-09 09:30:00

適配器模式設(shè)計(jì)模式代碼

2022-09-07 07:05:25

跨域問(wèn)題安全架構(gòu)

2022-07-26 09:03:50

冪等性數(shù)據(jù)狀態(tài)機(jī)

2023-11-08 14:03:47

數(shù)據(jù)可視化數(shù)字化轉(zhuǎn)型

2022-06-13 10:07:13

物聯(lián)網(wǎng)開(kāi)發(fā)物聯(lián)網(wǎng)

2023-10-06 00:16:21

RedisMySQL事務(wù)

2024-10-15 09:25:08

JDBCMybatis數(shù)據(jù)庫(kù)

2023-02-15 07:03:41

跨域問(wèn)題面試安全

2019-04-26 13:01:16

ServiceMesh微服務(wù)架構(gòu)

2020-06-15 08:06:25

ES數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)