上海網(wǎng)站備案信息免費(fèi)發(fā)帖推廣的平臺
一. 事務(wù)的特性
ACID
- 原子性 --> 事務(wù)操作被視為一個整體 , 要么全部成功 , 要么全部失敗
- 一致性 --> 事務(wù)操作前后數(shù)據(jù)的變化是一致的
- 隔離性 --> 事務(wù)的執(zhí)行不受其他事務(wù)的影響
- 持久性 --> 事務(wù)執(zhí)行完畢會對數(shù)據(jù)永久保存
比如我們在轉(zhuǎn)賬的過程中 , A給B轉(zhuǎn)賬1000元 , 在轉(zhuǎn)賬過程會對A的余額扣減 , B的余額增加 , 這是兩個過程但在一個事務(wù)中會被視為一個整體 , 不可能出現(xiàn)A扣減成功 , B增加失敗這種情況 , 這就是事務(wù)的原子性 . 而對于一致性我們可以理解為iA減少了1000塊 , 那B必然會增加1000塊 , 這個數(shù)據(jù)的變化是一致的. 對應(yīng)隔離性 , 也就是我們在轉(zhuǎn)賬的過程中 , 是不會收到其他業(yè)務(wù)操作的影響 .
=============================================================
**面試官:**事務(wù)的特性是什么?可以詳細(xì)說一下嗎?
**候選人:**嗯,這個比較清楚,ACID,分別指的是:原子性、一致性、隔離性、持久性;我舉個例子:
A向B轉(zhuǎn)賬500,轉(zhuǎn)賬成功,A扣除500元,B增加500元,原子操作體現(xiàn)在要么都成功,要么都失敗
在轉(zhuǎn)賬的過程中,數(shù)據(jù)要一致,A扣除了500,B必須增加500
在轉(zhuǎn)賬的過程中,隔離性體現(xiàn)在A像B轉(zhuǎn)賬,不能受其他事務(wù)干擾
在轉(zhuǎn)賬的過程中,持久性體現(xiàn)在事務(wù)提交后,要把數(shù)據(jù)持久化(可以說是落盤操作)
二. 并發(fā)事務(wù)問題
并發(fā)事務(wù)會產(chǎn)生哪些問題?
- 臟讀: 一個事務(wù)讀取到其他事務(wù)還未提交的數(shù)據(jù)
- 不可重復(fù)讀: 一個事務(wù)在第一次讀取某個數(shù)據(jù)的時候 , 得到一個結(jié)果 , 此時其他事務(wù)對該數(shù)據(jù)進(jìn)行了修改 , 導(dǎo)致原事務(wù)在再次讀取的時候讀取的數(shù)據(jù)和第一次讀取的不相同
- 幻讀: 一個數(shù)據(jù)在多次讀取某個數(shù)據(jù)的過程中 , 其他事務(wù)對數(shù)據(jù)就行了增刪 , 導(dǎo)致原事務(wù)再次讀取數(shù)據(jù)獲得的結(jié)果比原數(shù)據(jù)多了或者少了 , 就像出現(xiàn)幻覺一樣
如何解決并發(fā)事務(wù)問題?
在Mysql的隔離機(jī)制當(dāng)中有對上述情況就行處理的方式
Mysql的隔離機(jī)制共包含四種
- 讀未提交 --> 上述三種問題都不能解決
- 讀已提交 --> 可以解決臟讀問題
- 可重復(fù)讀 --> 可以解決臟讀與不可重復(fù)讀問題 , 是Mysql的默認(rèn)事務(wù)隔離級別
- 串行話 --> 上述三種問題都可以解決 , 但是其執(zhí)行效率慢 , 不建議使用
=============================================================
面試官:并發(fā)事務(wù)帶來哪些問題?
候選人:
我們在項(xiàng)目開發(fā)中,多個事務(wù)并發(fā)進(jìn)行是經(jīng)常發(fā)生的,并發(fā)也是必然的,有可能導(dǎo)致一些問題
第一是臟讀, 當(dāng)一個事務(wù)正在訪問數(shù)據(jù)并且對數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫中,這時另外一個事務(wù)也訪問了這個數(shù)據(jù),因?yàn)檫@個數(shù)據(jù)是還沒有提交的數(shù)據(jù),那么另外一個事務(wù)讀到的這個數(shù)據(jù)是“臟數(shù)據(jù)”,依據(jù)“臟數(shù)據(jù)”所做的操作可能是不正確的。
第二是不可重復(fù)讀:比如在一個事務(wù)內(nèi)多次讀同一數(shù)據(jù)。在這個事務(wù)還沒有結(jié)束時,另一個事務(wù)也訪問該數(shù)據(jù)。那么,在第一個事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個事務(wù)的修改導(dǎo)致第一個事務(wù)兩次讀取的數(shù)據(jù)可能不太一樣。這就發(fā)生了在一個事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的情況,因此稱為不可重復(fù)讀。
第三是幻讀(Phantom read):幻讀與不可重復(fù)讀類似。它發(fā)生在一個事務(wù)(T1)讀取了幾行數(shù)據(jù),接著另一個并發(fā)事務(wù)(T2)插入了一些數(shù)據(jù)時。在隨后的查詢中,第一個事務(wù)(T1)就會發(fā)現(xiàn)多了一些原本不存在的記錄,就好像發(fā)生了幻覺一樣,所以稱為幻讀。
面試官:怎么解決這些問題呢?MySQL的默認(rèn)隔離級別是?
候選人:解決方案是對事務(wù)進(jìn)行隔離
MySQL支持四種隔離級別,分別有:
第一個是,未提交讀(read uncommitted)它解決不了剛才提出的所有問題,一般項(xiàng)目中也不用這個。第二個是讀已提交(read committed)它能解決臟讀的問題的,但是解決不了不可重復(fù)讀和幻讀。第三個是可重復(fù)讀(repeatable read)它能解決臟讀和不可重復(fù)讀,但是解決不了幻讀,這個也是mysql默認(rèn)的隔離級別。第四個是串行化(serializable)它可以解決剛才提出來的所有問題,但是由于讓是事務(wù)串行執(zhí)行的,性能比較低。所以,我們一般使用的都是mysql默認(rèn)的隔離級別:可重復(fù)讀
三. undo_log和redo_log
1. 什么是undo_log
undo_log是一種邏輯日志他記錄的命令和原有命名是相反的 , 就比如我現(xiàn)在執(zhí)行一條插入命令 , 在undo_log中就會保存與之邏輯相同的刪除日志 , 主要用來保證事務(wù)中的原子性 , 一致性
2. 什么是redo_log
undo_log簡單來說就是Mysql用來保證事務(wù)持久性所采取的一種策略 , 在mysql的事務(wù)提交過程中 , mysql需要將內(nèi)存當(dāng)中的數(shù)據(jù)保存到磁盤中 ,而mysql會在內(nèi)存當(dāng)中創(chuàng)建一個緩沖區(qū) , 他不會在磁盤中直接對數(shù)據(jù)就行修改 , 而是在這個緩沖區(qū)當(dāng)中修改數(shù)據(jù)再提交 , 對于mysql的數(shù)據(jù)是通過頁表的形式進(jìn)行保存 , 一張頁表也就是代表著表中的一條數(shù)據(jù) , 在食物提交之前會在緩沖區(qū)中查詢該數(shù)據(jù)是否存在于緩存區(qū) , 緩沖區(qū)會保存一些常用數(shù)據(jù) , 如果數(shù)據(jù)不存在就會向磁盤中請求獲取數(shù)據(jù).
那么在緩沖區(qū)對數(shù)據(jù)進(jìn)行修改之后 , 就會觸發(fā)提交 , 但是在這個提交過程當(dāng)中如果mysql出現(xiàn)故障導(dǎo)致宕機(jī) , 那么我們事務(wù)的數(shù)據(jù)就會丟失 , 這種情況肯定是不被允許的. 因此mysql采用了redolog日志的方式來解決該問題
redo_log也就是當(dāng)事務(wù)提交前會優(yōu)先記錄改事務(wù)的操作并保存到與緩沖區(qū)同級的redo_log緩沖區(qū)當(dāng)中 , redo_log緩沖區(qū)在接受到該日志信息后會立即同步到磁盤的redo_log file文件中 , 該過程是通過追加方式進(jìn)行保存 , 執(zhí)行速度非???, 當(dāng)服務(wù)異常宕機(jī)并出現(xiàn)臟頁數(shù)據(jù)時 , 再重啟后就會讀取該日志文件更新數(shù)據(jù)
四. 分布式事務(wù)
分布式事務(wù)通常用在分布式環(huán)境對多個服務(wù)多張表的修改當(dāng)中 , 在我近期的物流項(xiàng)目當(dāng)中也是采用了seata來處理分布式事務(wù)
seata的AT模式實(shí)現(xiàn)原理
AT模式是優(yōu)先保證數(shù)據(jù)的可用性 , 其執(zhí)行流程共分為兩步
第一步:
在聲明了分布式注解并運(yùn)行時 , seata會首先在全局事務(wù)表中注冊該次事務(wù)的信息 , 對于事務(wù)中的所有分支 , 會被看做資源管理器 , 所有的資源管理器都會注冊在事務(wù)管理器當(dāng)中( 事務(wù)管理器是對所有資源進(jìn)行統(tǒng)籌的 ) , 并在分支事務(wù)表中寫入該事物的信息 . 在上述流程執(zhí)行完畢后 , 資源管理器會對所有分支按順序執(zhí)行 , 在每個分支的執(zhí)行過程中 , 會在執(zhí)行前與執(zhí)行后分別從數(shù)據(jù)庫中查詢該數(shù)據(jù)信息并記錄在undo_log日志當(dāng)中 , 被稱為前鏡像與后鏡像 , 并像事務(wù)管理器報告執(zhí)行情況;
第二步:
在所有分支事務(wù)執(zhí)行完畢之后 , 事務(wù)管理器會對各分支執(zhí)行情況就行統(tǒng)籌 , 如果執(zhí)行出現(xiàn)錯誤 , 需要執(zhí)行回滾 , seata就會通過undo_log中的前后鏡像對數(shù)據(jù)進(jìn)行回滾