亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入探究MySQL事務實現(xiàn)原理

 更新時間:2023年06月14日 10:53:25   作者:半畝方塘立身  
數(shù)據(jù)庫事務是指一組數(shù)據(jù)庫操作,這些操作必須被視為一個不可分割的單元,要么全部執(zhí)行成功,要么全部失敗回滾,本文詳細的給大家介紹了MySQL事務的實現(xiàn)原理,對我們學習MySQL有一定的幫助,感興趣的同學可以跟著小編一起來探究

什么是數(shù)據(jù)庫事務

數(shù)據(jù)庫事務是指一組數(shù)據(jù)庫操作,這些操作必須被視為一個不可分割的單元,要么全部執(zhí)行成功,要么全部失敗回滾。事務通常由多個SQL語句組成,這些語句可以讀取、插入、更新或刪除數(shù)據(jù)庫中的數(shù)據(jù)。
事務具有ACID屬性:

  • 原子性(Atomicity):事務的所有操作被視為單個原子操作,要么全部執(zhí)行成功,要么全部執(zhí)行失敗回滾。
  • 一致性(Consistency):事務執(zhí)行的結果必須使數(shù)據(jù)庫從一個一致性狀態(tài)轉換到另一個一致性狀態(tài),其中包括所有數(shù)據(jù)完整性和約束性規(guī)則的應用。
  • 隔離性(Isolation):一個事務的執(zhí)行不能被其他并發(fā)執(zhí)行的事務干擾,每個事務應該感覺自己在獨立地執(zhí)行。
  • 持久性(Durability):一旦事務提交,其結果應該持久保存在數(shù)據(jù)庫中,即使系統(tǒng)故障也應該如此。

通過實現(xiàn)事務,數(shù)據(jù)庫系統(tǒng)可以確保數(shù)據(jù)的完整性和一致性,以及并發(fā)訪問時的正確性。如果一個事務中的任何一個操作失敗,整個事務將被回滾到最初的狀態(tài),這確保了數(shù)據(jù)庫的一致性。

Mysql如何保證原子性

undo log名為回滾日志,是實現(xiàn)原子性的關鍵。 InnoDB把這些為了回滾而記錄的這些東西稱之為undo log。這里需要注意的一點是,由于查詢操作(SELECT)并不會修改任何用戶記錄,所以在查詢操作執(zhí)行時,并不需要記錄相應的undo log。undo log主要分為3種:

  • Insert undo log :插入一條記錄時,至少要把這條記錄的主鍵值記下來,之后回滾的時候只需要把這個主鍵值對應的記錄刪掉就好了。

  • Update undo log:修改一條記錄時,至少要把修改這條記錄前的舊值都記錄下來,這樣之后回滾時再把這條記錄更新為舊值就好了。

  • Delete undo log:刪除一條記錄時,至少要把這條記錄中的內容都記下來,這樣之后回滾時再把由這些內容組成的記錄插入到表中就好了。

    • 刪除操作都只是設置一下老記錄的DELETED_BIT,并不真正將過時的記錄刪除。
    • 為了節(jié)省磁盤空間,InnoDB有專門的purge線程來清理DELETED_BIT為true的記錄。為了不影響MVCC的正常工作,purge線程自己也維護了一個read view(這個read view相當于系統(tǒng)中最老活躍事務的read view);如果某個記錄的DELETED_BIT為true,并且DB_TRX_ID相對于purge線程的read view可見,那么這條記錄一定是可以被安全清除的。

舉個栗子:

sqlundo log
insertdelete
deleteinsert
update T set v=3 where v=1update T set v=1 where v=3

Mysql如何保證持久性

我們了解到InnoDB 為了提升讀寫效率,引入了Buffer Pool(緩存池):

  • 當數(shù)據(jù)庫讀取數(shù)據(jù)時,會首先從緩存池中讀取
  • 往數(shù)據(jù)庫寫入數(shù)據(jù)時,會先寫入緩存池
  • 緩存池中更新的數(shù)據(jù)會定期刷新到磁盤中

如果MySQL宕機,緩存池中更新的數(shù)據(jù)還沒有刷回到磁盤中,就會導致數(shù)據(jù)丟失。于是,redo log被引入進來解決這個問題。

  • 先將原始數(shù)據(jù)從磁盤中讀入內存中來,修改數(shù)據(jù)的內存拷貝。
  • 生成一條重做日志并寫入redo log buffer,記錄的是數(shù)據(jù)被修改后的值。
  • 當事務commit時,將redo log buffer中的內容刷新到 redolog file,對 redo log file采用追加寫的方式。
  • 定期將內存中修改的數(shù)據(jù)刷新到磁盤中。

redoundo在一次事務操作中是如何交互的?假設有A、B兩個數(shù)據(jù),值分別為1、2,開啟事務分別對其進行修改A → 3,B → 4,在提交,過程如下:

事務redo&undo logo
begin;開啟事務
記錄A->3到redo log buffer
update T set A=3 where A=1;A修改為3
記錄A=1到undo log
記錄B->4到redo log buffer
update T set B=4 where B=2;B修改為4
記錄B=2到undo log
記錄A->3到redo log記錄B->4到redo log
commit;事務提交

MySQL怎么保證隔離性

事務在并發(fā)情形下會互相干擾到的操作大體可以分為兩類,與之相對應地,MySQL采用了兩種方式來實現(xiàn)它們的隔離:

  • 一個事務的寫操作對另一個事務的寫操作的影響:鎖機制保證隔離性
  • 一個事務的寫操作對另一個事務的讀操作的影響:MVCC保證隔離性

加鎖:讀取數(shù)據(jù)之前,對其加鎖,阻止其他事務對數(shù)據(jù)進行修改

MVCC:不加任何鎖,采用多版本并發(fā)控制實現(xiàn),把數(shù)據(jù)庫的行鎖和行的多個版本結合起來,可以實現(xiàn)非鎖定讀,從而提高數(shù)據(jù)庫的并發(fā)性能。

事務隔離級別

當數(shù)據(jù)庫上有多個事務同時執(zhí)行的時候,會帶來以下問題:

問題描述舉例
臟讀一個事務讀到了另一個事務未提交修改的數(shù)據(jù)。事務A開始一個更新操作,但是還沒有提交,這時事務B讀取了這個未提交的數(shù)據(jù),就會產生臟讀。
幻讀一個事務按相同的查詢條件重新讀取以前檢索過的數(shù)據(jù),卻發(fā)現(xiàn)其他事務插入了滿足其查詢條件的新數(shù)據(jù)。事務A進行一個范圍查詢,此時事務B插入了一些符合該范圍查詢條件的新數(shù)據(jù),當事務A再次進行相同的范圍查詢時,會發(fā)現(xiàn)多了一些之前沒有的行,就產生了幻讀。
不可重復讀在一個事務中,多次查詢的數(shù)據(jù)不一致。事務A讀取了一行數(shù)據(jù),然后事務B對這一行數(shù)據(jù)進行了更新,并且提交了,當事務A再次讀取這一行數(shù)據(jù)時,會發(fā)現(xiàn)數(shù)據(jù)已經發(fā)生了變化,就產生了不可重復讀。

為了避免這些問題的出現(xiàn),數(shù)據(jù)庫引入了隔離級別的概念,通過對不同隔離級別的設置,可以控制事務之間的隔離程度,從而避免并發(fā)問題的產生。不同的隔離級別有不同的特點和使用場景,需要根據(jù)實際情況進行選擇。

以下是四個標準的事務隔離級別:

隔離級別含義臟讀不可重復讀幻讀
讀未提交,Read Uncommitted事務中的修改,即使沒有提交,對其他事務都是可見的YYY
讀已提交,Read Committed事務從開始到提交之前,所做的修改對其他事務都不可見NYY
可重復讀,Repeatable read同一事務中多次讀取同樣的記錄結果是一致的NNY
可序列化,Serializable在讀取的每一行數(shù)據(jù)上加鎖,強制事務串行執(zhí)行NNN

臟讀的解決

Innodb是通過在每行數(shù)據(jù)中增加一個隱藏的事務ID來實現(xiàn)mvcc,當一個事物開始時他會獲取一個唯一的事務ID,該事務ID用來標記事務做的修改。當事務讀取一行數(shù)據(jù)時,innodb會檢查該行數(shù)據(jù)事務ID是否小于當前事務ID,如果是說明該行數(shù)據(jù)是未提交的數(shù)據(jù),innodb會阻止該事務讀取該行數(shù)據(jù),從而避免了臟讀的問題。

不可重復讀的解決

innodb通過mvcc解決不可重復讀的問題,在RR數(shù)據(jù)庫隔離級別下,當我們使用快照進行數(shù)據(jù)讀取的時候,只會在第一次讀取的時候生成一個ReadView,后續(xù)所有快照讀都是使用同一個快照,所以就不會發(fā)生不可重復讀的問題了。

可重復讀模式下舉個栗子: 事務隔離級別為RR:

創(chuàng)建個測試表,并插入一條數(shù)據(jù)(1,1,1)

create table table1(
    id int(11) not null,
? ? a varchar(50) default null,
? ? b varchar(50) default null,
? ? primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

分別開啟兩個事務測試:

幻讀的解決

innodb的mvcc和間隙鎖在一定程度上避免了幻讀的發(fā)生,但是沒有辦法完全避免,當一個事務讀的時候會導致幻讀的發(fā)生。

幻讀的case

  • 創(chuàng)建一個用戶表

create table user(
    id int not null,
    name varchar(50),
    age int,
    primary key(id)
);
  • 插入幾條數(shù)據(jù)
insert into user values(1,'張三',10),(2,'李四',20),(3,'王二',30);

  • 分別開啟兩個事務測試:

MVCC實現(xiàn)

每條記錄在更新的時候都會同時記錄一條回滾操作。同一條記錄在系統(tǒng)中可以存在多個版本,這就是數(shù)據(jù)庫的多版本并發(fā)控制(MVCC)。

MySQL中每條記錄,除了我們自定義的字段之外,還有數(shù)據(jù)庫隱藏定義的三個字段:

字段描述
DB_TRX_ID6字節(jié),最近修改事務id,記錄創(chuàng)建這套記錄后者最后一次修改該記錄的事務id
DB_ROLL_PTR7字節(jié),回滾指針,指向這條記錄的上一個版本,用于配合undolog
DB_ROW_ID6字節(jié),隱藏的主鍵,如果數(shù)據(jù)表沒有主鍵,那么innodb會生成一個6字節(jié)的row_id

在 MySQL 中,實際上每條記錄在更新的時候都會同時記錄一條回滾操作。記錄上的最新值,通過回滾操作,都可以得到前一個狀態(tài)的值。

InnoDB 并不會真正地去開辟空間存儲多個版本的行記錄,只是借助 undo log 記錄每次寫操作的反向操作。所以B+ 索引樹上對應的記錄只會有一個最新版本,InnoDB 可以根據(jù) undo log 得到數(shù)據(jù)的歷史版本,從而實現(xiàn)多版本控制。

Read View

什么是Read View,說白了Read View就是事務進行快照讀操作的時候生產的讀視圖(Read View),在該事務執(zhí)行的快照讀的那一刻,會生成數(shù)據(jù)庫系統(tǒng)當前的一個快照,記錄并維護系統(tǒng)當前活躍事務的ID(當每個事務開啟時,都會被分配一個ID, 這個ID是遞增的,所以最新的事務,ID值越大)

所以我們知道 Read View主要是用來做可見性判斷的, 即當我們某個事務執(zhí)行快照讀的時候,對該記錄創(chuàng)建一個Read View讀視圖,把它比作條件用來判斷當前事務能夠看到哪個版本的數(shù)據(jù),即可能是當前最新的數(shù)據(jù),也有可能是該行記錄的undo log里面的某個版本的數(shù)據(jù)。

Read View遵循一個可見性算法,主要是將要被修改的數(shù)據(jù)的最新記錄中的DB_TRX_ID(即當前事務ID)取出來,與系統(tǒng)當前其他活躍事務的ID去對比(由Read View維護),如果DB_TRX_ID跟Read View的屬性做了某些比較,不符合可見性,那就通過DB_ROLL_PTR回滾指針去取出Undo Log中的DB_TRX_ID再比較,即遍歷鏈表的DB_TRX_ID(從鏈首到鏈尾,即從最近的一次修改查起),直到找到滿足特定條件的DB_TRX_ID, 那么這個DB_TRX_ID所在的舊記錄就是當前事務能看見的最新老版本

假設一個值從 1 被按順序改成了 2、3、4,在回滾日志里面就會有類似下面的記錄。

當前值是 4,但是在查詢這條記錄的時候,不同時刻啟動的事務會有不同的 read-view。如圖中看到的,在視圖 A、B、C 里面,這一個記錄的值分別是 1、2、4,同一條記錄在系統(tǒng)中可以存在多個版本,就是數(shù)據(jù)庫的多版本并發(fā)控制(MVCC)。對于 read-view A,要得到 1,就必須將當前值依次執(zhí)行圖中所有的回滾操作得到。同時你會發(fā)現(xiàn),即使現(xiàn)在有另外一個事務正在將 4 改成 5,這個事務跟 read-view A、B、C 對應的事務是不會沖突的。你一定會問,回滾日志總不能一直保留吧,什么時候刪除呢?答案是,在不需要的時候才刪除。也就是說,系統(tǒng)會判斷,當沒有事務再需要用到這些回滾日志時,回滾日志會被刪除。什么時候才不需要了呢?就是當系統(tǒng)里沒有比這個回滾日志更早的 read-view 的時候。

RC、RR級別下的InnoDB快照讀有什么不同?

在可重復讀隔離級別下,只需要在事務開始的時候創(chuàng)建一致性視圖,之后事務里的其他查詢都共用這個一致性視圖;

在讀提交隔離級別下,每一個語句執(zhí)行前都會重新算出一個新的視圖。

以上就是深入探究MySQL事務實現(xiàn)原理的詳細內容,更多關于MySQL 事務的資料請關注腳本之家其它相關文章!

相關文章

最新評論