InnoDB事務的ACID特性和實現

2021-10-19 07:14:41 字數 4523 閱讀 8061

1、acid特性

2、redo日誌

3、undo日誌

4、事務的4種隔離級別

事務可以由非常簡單的sql語句組成,也可以由一組複雜的sql語句組成,原子性要求事務的操作中,要麼都做,要麼都不做,事務中的任何一條sql語句執行失敗,已經執行成功的sql語句也必須撤銷,資料庫的狀態應回到執行事務前的狀態。原子性由undo日誌來實現。

事務的一致性指的是資料庫從一種狀態轉變為下一種一致的狀態。在事務開始之前和事務結束以後,資料庫的完整性約束沒有被破壞。一致性通常由undo日誌來實現。

事務的隔離性要求每個讀寫事務的物件對其他事務的操作物件能相互分離,即該事務提交前對其他事務都不可見,隔離性通常這使用來實現。

事務的永續性要求事務一旦提交,其結果就是永久性的,即使發生宕機等故障,資料庫也能將資料恢復。永續性通常使用redo日誌來實現。

redo日誌用來實現事務的永續性,其由兩部分組成:一是記憶體中的重做日誌緩衝(redo log buffer),其是易失性的;二是重做日誌檔案(redo log file),其是永續性的。每次事務提交時,必須先將該事務的所有日誌寫入到重做日誌檔案進行持久化,待事務的commit操作完成才算完成。每次將重做日誌緩衝寫入重做日誌檔案後,innodb引擎都需要呼叫一次fsync操作。因為重做日誌緩衝寫入重做日誌檔案時,是先寫入檔案系統快取的,為了確保重做日誌寫入磁碟,必須進行一次fsync操作。

重做日誌都是以512b進行儲存的,意味這重做日誌緩衝和重做日誌檔案都是以block方式進行儲存的,稱為重做日誌塊(redo log block),如果乙個頁中產生的重做日誌數量大於512b,那麼需要分割為多個重做日誌塊進行儲存。由於重做日誌塊和磁碟扇區大小一樣,都是512位元組,因此重做日誌寫入可以保證原子性,不需要doublewrite。

log block由三部分所構成,分別是日誌塊頭(log block header)日誌塊尾(log block tailer)日誌本身。日誌頭占用12位元組,日誌尾占用8位元組。故每個塊實際儲存日誌的大小為492位元組

lsn是log sequence number的縮寫,其代表的是日誌序列號,在innodb儲存引擎中,lsb占用8位元組,並且單調遞增,lsn表示的含義有:

lsn不僅記錄在重做日誌中,還存在於每個頁中。在每個頁的頭部,有乙個值fil_page_lsn,記錄了該頁的lsn,在頁中,lsn表示該頁最後重新整理時lsn的大小。因為重做日誌記錄的是每個頁的日誌,因此頁中的lsn用來判斷頁是否需要進行恢復操作。    

資料庫啟動時,不管上次資料庫執行是否正常關閉,都會嘗試進行恢復操作。例如頁p1的lsn為1000,而資料庫啟動時,檢測到衝日日誌的lsn為1300,並且該事務已經提交,那麼資料庫需要進行恢復操作,將重做日誌應用到該頁中。同樣的,對於重做日誌中lsn小於p1頁的lsn,不需要進行重做,因為p1頁的lsn表示頁已經重新整理到該位置。

undo日誌用來幫助事務回滾和mvcc功能。當innodb回滾時,它實際上做的是與先前相反的工作,對於每個insert,引擎會完成乙個delete,對於每個delete,引擎會執行乙個insert,對於每個update,引擎會執行乙個相反的update。

事務提交後不能馬上刪除undo log和undo log所在的頁,這時因為可能還有其他事務需要通過undo log得到行記錄之前的版本。因此事務提交時將undo log放入乙個鍊錶中,是否最終刪除由purge執行緒來判斷。

innodb中,undo log分為:

purge操作是清理之前的delete和update操作,將上述操作最終完成。

在介紹事務的4種隔離級別之前,我們先介紹幾個概念,分別是髒讀、不可重複讀、幻讀。

髒資料是指事務對緩衝池中的行記錄的修改,並且還沒有被提交。髒讀是指讀到了髒資料,即乙個事務讀到了另乙個事務中未提交的資料,這顯然違反了資料庫的隔離性。

不可重複讀是指同乙個事務內多次讀取同乙個資料集合,在這個事務還沒有結束時,另外乙個事務也訪問了同一資料集合,並且做了一些dml操作。因此,在第乙個事務中的兩次讀資料之間,由於第二個事務的修改,那麼第乙個事務兩次讀到的資料可能是不同的。這樣就發生了乙個事務內兩次讀到的資料是不一樣的情況,這種情況稱為不可重複讀。不可重複讀的側重點在於delete和updata操作。

指的是在同一事務下,連續執行兩次同樣的sql語句可能導致不同的結果,第二次的結果可能會返回之前不存在的行。幻讀的側重點在於insert操作。

innodb的隔離性主要通過鎖和mvcc機制來實現的,使用不同的行鎖演算法和mvcc策略,可以實現不同的隔離級別。innodb主要有兩種鎖,分別是共享鎖(s lock)和排它鎖(x lock),innodb有以下幾種行鎖的演算法,分別是:record lock、gap lock和next-key lock

select ... for update     # 對讀取的行加乙個x鎖

select ... lock in share mode # 對讀取的行加乙個s鎖

select * from z where b = 3 for update
進行查詢時,對於聚集索引,僅對第一列等於5加上record lock,而對於輔助索引,其加上的是next-key lock,鎖定的範圍是(1, 3),此外,innodb還會對輔助索引的下乙個鍵值加上gap lock,即還有乙個輔助索引範圍為(3,6),因此,如果在新會話b中執行sql語句,都會被阻塞。

select * from z where a = 5 lock in share mode

insert into z select 4,2

insert into z select 6,5

上面的例子中,gap lock的作用是為了阻止多個事務將記錄插入到同乙個範圍之內,而這會導致幻讀問題的產生。 在innodb儲存引擎中,對於insert操作,其會檢查插入記錄的下一條記錄是否被鎖定,若已經被鎖定,則不允許查詢。

含義:在該隔離級別,select語句不加鎖,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用於實際應用,因為它的效能也不比其他級別好多少。讀取未提交的資料,也被稱之為髒讀(dirty read)。

實現:讀資料不加鎖,寫資料加排它鎖。所有寫操作都會加排它鎖,那還怎麼讀未提交呢?前面我們介紹排它鎖的時候,有這種說明: 排他鎖會阻止其它事務再對其鎖定的資料加讀或寫的鎖,但是對不加鎖的讀就不起作用了。

含義:這是大多數資料庫系統的預設隔離級別(但不是mysql預設的)。它滿足了隔離的簡單定義:乙個事務只能看見已經提交事務所做的改變。這種隔離級別也支援所謂的不可重複讀(nonrepeatable read),因為同一事務的其他例項在該例項處理其間可能會有新的commit,所以同一select可能返回不同結果。

實現:寫資料時,使用排它鎖, 讀取資料不加鎖而是使用了mvcc機制。因此,在讀已提交的級別下,都會通過mvcc獲取當前資料的最新快照,不加任何鎖,也無視任何鎖(因為歷史資料是構造出來的,身上不可能有鎖)。但是,該級別下還是遺留了不可重複讀和幻讀問題:mvcc版本的生成時機: 是每次select時。這就意味著,如果我們在事務a中執行多次的select,在每次select之間有其他事務更新了我們讀取的資料並提交了,那就出現了不可重複讀,即:重複讀時,會出現資料不一致問題,後面我們會講解超支現象,就是這種引起的。

含義:這是mysql的預設事務隔離級別,它確保同一事務的多個例項在併發讀取資料時,會看到同樣的資料行。不過理論上,這會導致另乙個棘手的問題:幻讀 (phantom read)。簡單的說,幻讀指當使用者讀取某一範圍的資料行時,另乙個事務又在該範圍內插入了新行,當使用者再讀取該範圍的資料行時,會發現有新的「幻影」 行。innodb儲存引擎在repeatable read事務隔離級別下,使用next-key lock的演算法,避免了幻讀的產生。所以說,innodb儲存引擎在預設的隔離級別下事務的隔離級別已經完全保證了事務的隔離性要求,即達到sql的serializable隔離級別。

實現:寫資料時使用排它鎖,讀資料時使用mvcc。該級別與提交讀不同的是mvcc版本的生成時機,即:一次事務中只在第一次select時生成版本,後續的查詢都是在這個版本上進行,從而實現了可重複讀。但是不加讀鎖的select會導致大量的幻讀,可以通過next-key lock解決幻讀問題。

含義:這是最高的隔離級別,它通過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每個讀的資料行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。可序列化通常只有在分布式事務中才用到。

實現:寫資料時加排它鎖,讀資料時自動加共享鎖,即對每個select語句後自動加上lock in share mode。在這種情況時,讀占用了鎖,對一致性非鎖定讀不再予以支援,事務基本只能序列執行。

事務特性(ACID)

原子性 是指事務乙個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。不能夠單獨執行。把一組操作放入事務中 一致性 事務的執行的前後,資料的完整性要得到保證。隔離性 強調的是多個使用者併發訪問資料庫的時候,乙個使用者事務不能被其他使用者的事務所干擾到,多個併發事務之間的資料要相互隔離。解決多...

事務ACID特性

所謂事務,它是乙個操作序列,這些操作要麼都執行,要麼都不執行,它是乙個不可分割的工作單位。例如,銀行轉帳工作 從乙個帳號扣款並使另乙個帳號增款,這兩個操作要麼都執行,要麼都不執行。資料庫事務必須具備acid特性,acid是atomic 原子性 consistency 一致性 isolation 隔離...

事務ACID特性

所謂事務,它是乙個操作序列,這些操作要麼都執行,要麼都不執行,它是乙個不可分割的工作單位。例如,銀行轉帳工作 從乙個帳號扣款並使另乙個帳號增款,這兩個操作要麼都執行,要麼都不執行。資料庫事務必須具備acid特性,acid是atomic 原子性 consistency 一致性 isolation 隔離...