做英語趣味教具的網(wǎng)站時(shí)事新聞最新2022
事務(wù)由哪些特性
-
原子性(Atomicity):一個(gè)事務(wù)中的所有操作,要么全部完成,要么全部不完成,不會結(jié)束在中間某個(gè)環(huán)節(jié),而且事務(wù)在執(zhí)行過程中發(fā)生錯(cuò)誤,會被回滾到事務(wù)開始前的狀態(tài),就像這個(gè)事務(wù)從來沒有執(zhí)行過一樣
-
一致性(Consistency):是指事務(wù)操作前和操作后,數(shù)據(jù)滿足完整性約束,數(shù)據(jù)庫保持一致性狀態(tài)。
-
隔離性(Isolation):數(shù)據(jù)庫允許多個(gè)并發(fā)事務(wù)同時(shí)對其數(shù)據(jù)進(jìn)行讀寫和修改的能力,隔離性可以防止多個(gè)事務(wù)并發(fā)執(zhí)行時(shí)由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致,因?yàn)槎鄠€(gè)事務(wù)同時(shí)使用相同的數(shù)據(jù)時(shí),不會相互干擾,每個(gè)事務(wù)都有一個(gè)完整的數(shù)據(jù)空間,對其他并發(fā)事務(wù)是隔離的。
-
持久性(Durability):事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失。
-
InnoDB 引擎通過什么技術(shù)來保證事務(wù)的這四個(gè)特性的呢?
-
持久性是通過 redo log (重做日志)來保證的;
-
原子性是通過 undo log(回滾日志) 來保證的;
-
隔離性是通過 MVCC(多版本并發(fā)控制) 或鎖機(jī)制來保證的;
-
一致性則是通過持久性+原子性+隔離性來保證;
-
并行事務(wù)會引發(fā)什么
-
在同時(shí)處理多個(gè)事務(wù)的時(shí)候,就可能出現(xiàn)臟讀(dirty read)、不可重復(fù)讀(non-repeatable read)、幻讀(phantom read)的問題。
-
臟讀
-
如果一個(gè)事務(wù)「讀到」了另一個(gè)「未提交事務(wù)修改過的數(shù)據(jù)」,就意味著發(fā)生了「臟讀」現(xiàn)象。
-
如果在上面這種情況事務(wù) A 發(fā)生了回滾,那么事務(wù) B 剛才得到的數(shù)據(jù)就是過期的數(shù)據(jù),這種現(xiàn)象就被稱為臟讀。
-
-
不可重復(fù)讀
-
在一個(gè)事務(wù)內(nèi)多次讀取同一個(gè)數(shù)據(jù),如果出現(xiàn)前后兩次讀到的數(shù)據(jù)不一樣的情況,就意味著發(fā)生了「不可重復(fù)讀」現(xiàn)象。
-
在這過程中如果事務(wù) B 更新了這條數(shù)據(jù),并提交了事務(wù),那么當(dāng)事務(wù) A 再次讀取該數(shù)據(jù)時(shí),就會發(fā)現(xiàn)前后兩次讀到的數(shù)據(jù)是不一致的,這種現(xiàn)象就被稱為不可重復(fù)讀。
-
-
幻讀
-
在一個(gè)事務(wù)內(nèi)多次查詢某個(gè)符合查詢條件的「記錄數(shù)量」,如果出現(xiàn)前后兩次查詢到的記錄數(shù)量不一樣的情況,就意味著發(fā)生了「幻讀」現(xiàn)象。
-
事務(wù)的隔離級別由哪些
-
臟讀、不可重復(fù)讀、幻讀」的現(xiàn)象嚴(yán)重性排序
-
使用四種隔離級別來規(guī)避這些現(xiàn)象,隔離級別越高,性能效率就越低
-
讀未提交(read uncommitted),指一個(gè)事務(wù)還沒提交時(shí),它做的變更就能被其他事務(wù)看到;
-
讀提交(read committed),指一個(gè)事務(wù)提交之后,它做的變更才能被其他事務(wù)看到;
-
可重復(fù)讀(repeatable read),指一個(gè)事務(wù)執(zhí)行過程中看到的數(shù)據(jù),一直跟這個(gè)事務(wù)啟動時(shí)看到的數(shù)據(jù)是一致的,MySQL InnoDB 引擎的默認(rèn)隔離級別;只能看見啟動事務(wù)時(shí)的數(shù)據(jù)
-
串行化(serializable );會對記錄加上讀寫鎖,在多個(gè)事務(wù)對這條記錄進(jìn)行讀寫操作時(shí),如果發(fā)生了讀寫沖突的時(shí)候,后訪問的事務(wù)必須等前一個(gè)事務(wù)執(zhí)行完成,才能繼續(xù)執(zhí)行;
-
不同的隔離級別,并發(fā)事務(wù)時(shí)可能發(fā)生的現(xiàn)象也會不同
-
MySQL 雖然支持 4 種隔離級別,但是與SQL 標(biāo)準(zhǔn)中規(guī)定的各級隔離級別允許發(fā)生的現(xiàn)象卻有些出入
-
-
如何設(shè)置事務(wù)的隔離級別
-
修改事務(wù)的隔離級別:SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level;
-
level: {REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED | SERIALIZABLE }
-
-
在 SET 關(guān)鍵字后可以放置 GLOBAL 關(guān)鍵字、 SESSION 關(guān)鍵字或者什么都不放,這樣會對不同范圍的事務(wù)產(chǎn)生不同的影響
-
使用 GLOBAL 關(guān)鍵字(在全局范圍影響)
-
使用 SESSION 關(guān)鍵字(在會話范圍影響)
-
上述兩個(gè)關(guān)鍵字都不用(只對執(zhí)行語句后的下一個(gè)事務(wù)產(chǎn)生影響)
-
-
-
MySQL InnoDB 引擎的默認(rèn)隔離級別雖然是「可重復(fù)讀」,但是它很大程度上避免幻讀現(xiàn)象(并不是完全解決了)解決的方案有兩種:
-
針對快照讀(普通 select 語句),是通過 MVCC 方式解決了幻讀,因?yàn)榭芍貜?fù)讀隔離級別下,事務(wù)執(zhí)行過程中看到的數(shù)據(jù),一直跟這個(gè)事務(wù)啟動時(shí)看到的數(shù)據(jù)是一致的,即使中途有其他事務(wù)插入了一條數(shù)據(jù),是查詢不出來這條數(shù)據(jù)的,所以就很好了避免幻讀問題。
-
針對當(dāng)前讀(select ... for update 等語句),是通過 next-key lock(記錄鎖+間隙鎖)方式解決了幻讀,因?yàn)楫?dāng)執(zhí)行 select ... for update 語句的時(shí)候,會加上 next-key lock,如果有其他事務(wù)在 next-key lock 鎖范圍內(nèi)插入了一條記錄,那么這個(gè)插入語句就會被阻塞,無法成功插入,所以就很好了避免幻讀問題。
-
-
四種隔離級別具體是如何實(shí)現(xiàn)的呢?
-
對于「讀未提交」隔離級別的事務(wù)來說,因?yàn)榭梢宰x到未提交事務(wù)修改的數(shù)據(jù),所以直接讀取最新的數(shù)據(jù)就好了;
-
對于「串行化」隔離級別的事務(wù)來說,通過加讀寫鎖的方式來避免并行訪問;
-
對于「讀提交」和「可重復(fù)讀」隔離級別的事務(wù)來說,它們是通過 Read View 來實(shí)現(xiàn)的,它們的區(qū)別在于創(chuàng)建 Read View 的時(shí)機(jī)不同,可以把 Read View 理解成一個(gè)數(shù)據(jù)快照,就像相機(jī)拍照那樣,定格某一時(shí)刻的風(fēng)景?!缸x提交」隔離級別是在「每個(gè)語句執(zhí)行前」都會重新生成一個(gè) Read View,而「可重復(fù)讀」隔離級別是「啟動事務(wù)時(shí)」生成一個(gè) Read View,然后整個(gè)事務(wù)期間都在用這個(gè) Read View。
-
-
執(zhí)行「開始事務(wù)」命令,并不意味著啟動了事務(wù)。在 MySQL 有兩種開啟事務(wù)的命令,分別是:
-
begin/start transaction 命令
-
事務(wù)的啟動時(shí)機(jī):執(zhí)行了第一條 select 語句,才是事務(wù)真正啟動的時(shí)機(jī)
-
-
start transaction with consistent snapshot 命令
-
事務(wù)的啟動時(shí)機(jī):執(zhí)行了 start transaction with consistent snapshot 命令,就會馬上啟動事務(wù)
-
-
Read View 在 MVCC 里是如何工作的?
-
假如另一個(gè)事務(wù)已經(jīng)修改了記錄但是尚未提交, 是不能直接讀取最新版本的記錄的,核心問題就是:需要判斷一下版本鏈中的哪個(gè)版本是當(dāng)前事務(wù)可見的,設(shè)計(jì) InnoDB 的人提出了一個(gè) ReadView 的概念。
-
Read View 結(jié)果及其作用
-
m_ids :指的是在創(chuàng)建 Read View 時(shí),當(dāng)前數(shù)據(jù)庫中「活躍事務(wù)」的事務(wù) id 列表,注意是一個(gè)列表,“活躍事務(wù)”指的就是,啟動了但還沒提交的事務(wù)。
-
min_trx_id :指的是在創(chuàng)建 Read View 時(shí),當(dāng)前數(shù)據(jù)庫中「活躍事務(wù)」中事務(wù) id 最小的事務(wù),也就是 m_ids 的最小值。
-
max_trx_id :這個(gè)并不是 m_ids 的最大值,而是創(chuàng)建 Read View 時(shí)當(dāng)前數(shù)據(jù)庫中應(yīng)該給下一個(gè)事務(wù)的 id 值,也就是全局事務(wù)中最大的事務(wù) id 值 + 1;
-
creator_trx_id :指的是創(chuàng)建該 Read View 的事務(wù)的事務(wù) id。
-
-
聚簇索引記錄中的兩個(gè)隱藏列
-
trx_id,當(dāng)一個(gè)事務(wù)對某條聚簇索引記錄進(jìn)行改動時(shí),就會把該事務(wù)的事務(wù) id 記錄在 trx_id 隱藏列里;
-
roll_pointer,每次對某條聚簇索引記錄進(jìn)行改動時(shí),都會把舊版本的記錄寫入到 undo 日志中,然后這個(gè)隱藏列是個(gè)指針,指向每一個(gè)舊版本記錄,于是就可以通過它找到修改前的記錄。
-
-
一個(gè)事務(wù)去訪問記錄的時(shí)候,除了自己的更新記錄總是可見之外,還有這幾種情況(可見就是可以讀取到數(shù)據(jù))
-
如果記錄的 trx_id 值小于 Read View 中的
min_trx_id
值,表示這個(gè)版本的記錄是在創(chuàng)建 Read View 前已經(jīng)提交的事務(wù)生成的,所以該版本的記錄對當(dāng)前事務(wù)可見。 -
如果記錄的 trx_id 值大于等于 Read View 中的
max_trx_id
值,表示這個(gè)版本的記錄是在創(chuàng)建 Read View 后才啟動的事務(wù)生成的,所以該版本的記錄對當(dāng)前事務(wù)不可見。 -
如果記錄的 trx_id 值在 Read View 的
min_trx_id
和max_trx_id
之間,需要判斷 trx_id 是否在 m_ids 列表中:-
如果記錄的 trx_id 在
m_ids
列表中,表示生成該版本記錄的活躍事務(wù)依然活躍著(還沒提交事務(wù)),所以該版本的記錄對當(dāng)前事務(wù)不可見。 -
如果記錄的 trx_id 不在
m_ids
列表中,表示生成該版本記錄的活躍事務(wù)已經(jīng)被提交,所以該版本的記錄對當(dāng)前事務(wù)可見。
-
-
-
通過「版本鏈」來控制并發(fā)事務(wù)訪問同一個(gè)記錄時(shí)的行為就叫 MVCC(多版本并發(fā)控制)
-
對該記錄每次更新后,都會將舊值放到一條 undo日志 中,就算是該記錄的一個(gè)舊版本,隨著更新次數(shù)的增多,所有的版本都會被 roll_pointer 屬性連接成一個(gè)鏈表,我們把這個(gè)鏈表稱之為 版本鏈 ,版本鏈的頭節(jié)點(diǎn)就是當(dāng)前記錄最新的值。另外,每個(gè)版本中還包含生成該版本時(shí)對應(yīng)的事務(wù)id ,這個(gè)信息很重要
-
-
MVCC整體操作的流程
-
獲取事務(wù)自己的版本號,也就是事務(wù)id
-
獲取到ReadView
-
查詢得到數(shù)據(jù),然后與ReadView中的事務(wù)版本進(jìn)行比較
-
如果不符合ReadView的規(guī)則,就需要從Undo log中獲取歷史快照
-
最后放回符合規(guī)則的數(shù)據(jù)
-
可重復(fù)讀是如何工作的?
-
可重復(fù)讀隔離級別是啟動事務(wù)時(shí)生成一個(gè) Read View,然后整個(gè)事務(wù)期間都在用這個(gè) Read View。
讀提交是如何工作的?
-
讀提交隔離級別是在每次讀取數(shù)據(jù)時(shí),都會生成一個(gè)新的 Read View。
-
事務(wù)期間的多次讀取同一條數(shù)據(jù),前后兩次讀的數(shù)據(jù)可能會出現(xiàn)不一致,因?yàn)榭赡苓@期間另外一個(gè)事務(wù)修改了該記錄,并提交了事務(wù)。