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