国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > MySQL > 正文

MySQL事務日志的特點有哪些

2024-07-24 12:33:18
字體:
來源:轉載
供稿:網友
  本篇內容主要講解“MySQL事務日志的特征有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“MySQL事務日志的特征有哪些”吧!

  一、MySQL事務
  事務是MySQL區別于NoSQL的重要特征,是保證關系型數據庫數據一致性的關鍵技術。事務可看作是對數據庫操作的基本執行單元,可能包含一個或者多個SQL語句。這些語句在執行時,要么都執行,要么都不執行。
 
  事務的執行主要包括兩個操作,提交和回滾。
 
  提交:commit,將事務執行結果寫入數據庫。
 
  回滾:rollback,回滾所有已經執行的語句,返回修改之前的數據。
 
  MySQL事務包含四個特性,號稱ACID四大天王。
 
  原子性(Atomicity) :語句要么全執行,要么全不執行,是事務最核心的特性,事務本身就是以原子性來定義的;實現主要基于undo log日志實現的。
 
  持久性(Durability  :保證事務提交后不會因為宕機等原因導致數據丟失;實現主要基于redo log日志。
 
  隔離性(Isolation) :保證事務執行盡可能不受其他事務影響;InnoDB默認的隔離級別是RR,RR的實現主要基于鎖機制、數據的隱藏列、undo log和類next-key lock機制。
 
  一致性(Consistency) :事務追求的最終目標,一致性的實現既需要數據庫層面的保障,也需要應用層面的保障。
 
  隔離性
  原子性和持久性是單個事務本身層面的性質,而隔離性是指事務之間應該保持的關系。隔離性要求不同事務之間的影響是互不干擾的,一個事務的操作與其它事務是相互隔離的。
 
  由于事務可能并不只包含一條SQL語句,所以在事務的執行期間很有可能會有其它事務開始執行。因此多事務的并發性就要求事務之間的操作是相互隔離的。這一點跟多線程之間數據同步的概念有些類似。

  原子性
  事務的原子性就如原子操作一般,表示事務不可再分,其中的操作要么都做,要么都不做;如果事務中一個SQL語句執行失敗,則已執行的語句也必須回滾,數據庫退回到事務前的狀態。只有0和1,沒有其它值。
 
  事務的原子性表明事務就是一個整體,當事務無法成功執行的時候,需要將事務中已經執行過的語句全部回滾,使得數據庫回歸到最初未開始事務的狀態。
 
  事務的原子性就是通過undo log日志進行實現的。當事務需要進行回滾時,InnoDB引擎就會調用undo log日志進行SQL語句的撤銷,實現數據的回滾。
 
  持久性
  事務的持久性是指當事務提交之后,數據庫的改變就應該是永久性的,而不是暫時的。這也就是說,當事務提交之后,任何其它操作甚至是系統的宕機故障都不會對原來事務的執行結果產生影響。
 
  事務的持久性是通過InnoDB存儲引擎中的redo log日志來實現的,具體實現思路見下文。
 
  鎖機制
 
  事務之間的隔離,是通過鎖機制實現的。當一個事務需要對數據庫中的某行數據進行修改時,需要先給數據加鎖;加了鎖的數據,其它事務是不運行操作的,只能等待當前事務提交或回滾將鎖釋放。
 
  鎖機制并不是一個陌生的概念,在許多場景中都會利用到不同實現的鎖對數據進行保護和同步。而在MySQL中,根據不同的劃分標準,還可將鎖分為不同的種類。
 
  按照粒度劃分:行鎖、表鎖、頁鎖
 
  按照使用方式劃分:共享鎖、排它鎖
 
  按照思想劃分:悲觀鎖、樂觀鎖
 
  鎖機制的知識點很多,由于篇幅不好全部展開講。這里對按照粒度劃分的鎖進行簡單介紹。
 
  粒度:指數據倉庫的數據單位中保存數據的細化或綜合程度的級別。細化程度越高,粒度級就越小;相反,細化程度越低,粒度級就越大。
 
  MySQL按照鎖的粒度劃分可以分為行鎖、表鎖和頁鎖。
 
  行鎖:粒度最小的鎖,表示只針對當前操作的行進行加鎖;
 
  表鎖:粒度最大的鎖,表示當前的操作對整張表加鎖;
 
  頁鎖:粒度介于行級鎖和表級鎖中間的一種鎖,表示對頁進行加鎖。
 
  MySQL事務日志的特征有哪些
 
  數據庫的粒度劃分
 
  這三種鎖是在不同層次上對數據進行鎖定,由于粒度的不同,其帶來的好處和劣勢也不一而同。
 
  表鎖在操作數據時會鎖定整張表,因而并發性能較差;
 
  行鎖則只鎖定需要操作的數據,并發性能好。但是由于加鎖本身需要消耗資源(獲得鎖、檢查鎖、釋放鎖等都需要消耗資源),因此在鎖定數據較多情況下使用表鎖可以節省大量資源。
 
  MySQL中不同的存儲引擎能夠支持的鎖也是不一樣的。MyIsam只支持表鎖,而InnoDB同時支持表鎖和行鎖,且出于性能考慮,絕大多數情況下使用的都是行鎖。
 
  MVCC
 
  又是一個難嚼的大塊頭。MVCC就是用來實現上面的第三個隔離級別,可重復讀RR。
 
  MVCC:Multi-Version Concurrency Control,即多版本的并發控制協議。
 
  MVCC的特點就是在同一時刻,不同事務可以讀取到不同版本的數據,從而可以解決臟讀和不可重復讀的問題。
 
  MVCC實際上就是通過數據的隱藏列和回滾日志(undo log),實現多個版本數據的共存。這樣的好處是,使用MVCC進行讀數據的時候,不用加鎖,從而避免了同時讀寫的沖突。
 
  在實現MVCC時,每一行的數據中會額外保存幾個隱藏的列,比如當前行創建時的版本號和刪除時間和指向undo log的回滾指針。這里的版本號并不是實際的時間值,而是系統版本號。每開始新的事務,系統版本號都會自動遞增。事務開始時的系統版本號會作為事務的版本號,用來和查詢每行記錄的版本號進行比較。
 
  每個事務又有自己的版本號,這樣事務內執行數據操作時,就通過版本號的比較來達到數據版本控制的目的。
 
  另外,InnoDB實現的隔離級別RR時可以避免幻讀現象的,這是通過next-key lock機制實現的。
 
  next-key lock實際上就是行鎖的一種,只不過它不只是會鎖住當前行記錄的本身,還會鎖定一個范圍。比如上面幻讀的例子,開始查詢0<閱讀量<100的文章時,只查到了一個結果。next-key lock會將查詢出的這一行進行鎖定,同時還會對0<閱讀量<100這個范圍進行加鎖,這實際上是一種間隙鎖。間隙鎖能夠防止其他事務在這個間隙修改或者插入記錄。這樣一來,就保證了在0<閱讀量<100這個間隙中,只存在原來的一行數據,從而避免了幻讀。
 
  間隙鎖:封鎖索引記錄中的間隔
 
  雖然InnoDB使用next-key lock能夠避免幻讀問題,但卻并不是真正的可串行化隔離。再來看一個例子吧。
 
  MySQL事務日志的特征有哪些
 
  首先提一個問題:
 
  在T6時間,事務A提交事務之后,猜一猜文章A和文章B的閱讀量為多少?
 
  答案是,文章AB的閱讀量都被修改成了10000。這代表著事務B的提交實際上對事務A的執行產生了影響,表明兩個事務之間并不是完全隔離的。雖然能夠避免幻讀現象,但是卻沒有達到可串行化的級別。
 
  這還說明,避免臟讀、不可重復讀和幻讀,是達到可串行化的隔離級別的必要不充分條件。可串行化是都能夠避免臟讀、不可重復讀和幻讀,但是避免臟讀、不可重復讀和幻讀卻不一定達到了可串行化。
 
  一致性
 
  一致性是指事務執行結束后,數據庫的完整性約束沒有被破壞,事務執行的前后都是合法的數據狀態。
 
  一致性是事務追求的最終目標,原子性、持久性和隔離性,實際上都是為了保證數據庫狀態的一致性而存在的。
 
  這就不多說了吧。你細品。
 
  二、MySQL日志系統
  了解完MySQL的基本架構,大體上能夠對MySQL的執行流程有了比較清晰的認知。接下來我將為大家介紹一下日志系統。
 
  MySQL日志系統是數據庫的重要組件,用于記錄數據庫的更新和修改。若數據庫發生故障,可通過不同日志記錄恢復數據庫的原來數據。因此實際上日志系統直接決定著MySQL運行的魯棒性和穩健性。
 
  MySQL的日志有很多種,如二進制日志(binlog)、錯誤日志、查詢日志、慢查詢日志等,此外InnoDB存儲引擎還提供了兩種日志:redo log(重做日志)和undo log(回滾日志)。這里將重點針對InnoDB引擎,對重做日志、回滾日志和二進制日志這三種進行分析。
 
  重做日志(redo log)
 
  重做日志(redo log)是InnoDB引擎層的日志,用來記錄事務操作引起數據的變化,記錄的是數據頁的物理修改。
 
  重做日記的作用其實很好理解,我打個比方。數據庫中數據的修改就好比你寫的論文,萬一哪天論文丟了怎么呢?以防這種不幸的發生,我們可以在寫論文的時候,每一次修改都拿個小本本記錄一下,記錄什么時間對某一頁進行了怎么樣的修改。這就是重做日志。
 
  InnoDB引擎對數據的更新,是先將更新記錄寫入redo log日志,然后會在系統空閑的時候或者是按照設定的更新策略再將日志中的內容更新到磁盤之中。這就是所謂的預寫式技術(Write Ahead logging)。這種技術可以大大減少IO操作的頻率,提升數據刷新的效率。
 
  臟數據:指內存中未刷到磁盤的數據。
 
  redo log中最重要的概念就是緩沖池buffer pool,這是在內存中分配的一個區域,包含了磁盤中部分數據頁的映射,作為訪問數據庫的緩沖。
 
  當請求讀取數據時,會先判斷是否在緩沖池命中,如果未命中才會在磁盤上進行檢索后放入緩沖池;
 
  當請求寫入數據時,會先寫入緩沖池,緩沖池中修改的數據會定期刷新到磁盤中。這一過程也被稱之為刷臟 。
 
  因此,當數據修改時,除了修改buffer pool中的數據,還會在redo log中記錄這次操作;當事務提交時,會根據redo log的記錄對數據進行刷盤。如果MySQL宕機,重啟時可以讀取redo log中的數據,對數據庫進行恢復,從而保證了事務的持久性,使得數據庫獲得crash-safe能力。

  臟數據刷盤
 
  值得注意的是,redo log日志的大小是固定的,為了能夠持續不斷的對更新記錄進行寫入,在redo log日志中設置了兩個標志位置,checkpoint和write_pos,分別表示記錄擦除的位置和記錄寫入的位置。redo log日志的數據寫入示意圖可見下圖。
 
  當write_pos標志到了日志結尾時,會從結尾跳至日志頭部進行重新循環寫入。所以redo log的邏輯結構并不是線性的,而是可看作一個圓周運動。write_pos與checkpoint中間的空間可用于寫入新數據,寫入和擦除都是往后推移,循環往復的。
 
  當write_pos追上checkpoint時,表示redo log日志已經寫滿。這時不能繼續執行新的數據庫更新語句,需要停下來先刪除一些記錄,執行checkpoint規則騰出可寫空間。
 
  checkpoint規則:checkpoint觸發后,將buffer中臟數據頁和臟日志頁都刷到磁盤。

  臟日志刷盤
 
  除了上面提到的對于臟數據的刷盤,實際上redo log日志在記錄時,為了保證日志文件的持久化,也需要經歷將日志記錄從內存寫入到磁盤的過程。redo log日志可分為兩個部分,一是存在易失性內存中的緩存日志redo log buff,二是保存在磁盤上的redo log日志文件redo log file。
 
  為了確保每次記錄都能夠寫入到磁盤中的日志中,每次將redo log buffer中的日志寫入redo log file的過程中都會調用一次操作系統的fsync操作。
 
  fsync函數:包含在UNIX系統頭文件#include <unistd.h>中,用于同步內存中所有已修改的文件數據到儲存設備。
 
  在寫入的過程中,還需要經過操作系統內核空間的os buffer。redo log日志的寫入過程可見下圖。
 
  redo log日志刷盤流程
 
  二進制日志(binlog)
 
  二進制日志binlog是服務層的日志,還被稱為歸檔日志。binlog主要記錄數據庫的變化情況,內容包括數據庫所有的更新操作。所有涉及數據變動的操作,都要記錄進二進制日志中。因此有了binlog可以很方便的對數據進行復制和備份,因而也常用作主從庫的同步。
 
  這里binlog所存儲的內容看起來似乎與redo log很相似,但是其實不然。redo log是一種物理日志,記錄的是實際上對某個數據進行了怎么樣的修改;而binlog是邏輯日志,記錄的是SQL語句的原始邏輯,比如”給ID=2這一行的a字段加1 "。binlog日志中的內容是二進制的,根據日記格式參數的不同,可能基于SQL語句、基于數據本身或者二者的混合。一般常用記錄的都是SQL語句。
 
  這里的物理和邏輯的概念,我的個人理解是:
 
  物理的日志可看作是實際數據庫中數據頁上的變化信息,只看重結果,而不在乎是通過“何種途徑”導致了這種結果;
 
  邏輯的日志可看作是通過了某一種方法或者操作手段導致數據發生了變化,存儲的是邏輯性的操作。
 
  同時,redo log是基于crash recovery,保證MySQL宕機后的數據恢復;而binlog是基于point-in-time recovery,保證服務器可以基于時間點對數據進行恢復,或者對數據進行備份。
 
  事實上最開始MySQL是沒有redo log日志的。因為起先MySQL是沒有InnoDB引擎的,自帶的引擎是MyISAM。binlog是服務層的日志,因此所有引擎都能夠使用。但是光靠binlog日志只能提供歸檔的作用,無法提供crash-safe能力,所以InnoDB引擎就采用了學自于Oracle的技術,也就是redo log,這才擁有了crash-safe能力。這里對redo log日志和binlog日志的特點分別進行了對比:
 
  redo log與binlog的特點比較
 
  在MySQL執行更新語句時,都會涉及到redo log日志和binlog日志的讀寫。一條更新語句的執行過程如下:
 
  MySQL更新語句的執行過程
 
  從上圖可以看出,MySQL在執行更新語句的時候,在服務層進行語句的解析和執行,在引擎層進行數據的提取和存儲;同時在服務層對binlog進行寫入,在InnoDB內進行redo log的寫入。
 
  不僅如此,在對redo log寫入時有兩個階段的提交,一是binlog寫入之前prepare狀態的寫入,二是binlog寫入之后commit狀態的寫入。
 
  之所以要安排這么一個兩階段提交,自然是有它的道理的。現在我們可以假設不采用兩階段提交的方式,而是采用“單階段”進行提交,即要么先寫入redo log,后寫入binlog;要么先寫入binlog,后寫入redo log。這兩種方式的提交都會導致原先數據庫的狀態和被恢復后的數據庫的狀態不一致。
 
  先寫入redo log,后寫入binlog:
 
  在寫完redo log之后,數據此時具有crash-safe能力,因此系統崩潰,數據會恢復成事務開始之前的狀態。但是,若在redo log寫完時候,binlog寫入之前,系統發生了宕機。此時binlog沒有對上面的更新語句進行保存,導致當使用binlog進行數據庫的備份或者恢復時,就少了上述的更新語句。從而使得id=2這一行的數據沒有被更新。
 
  先寫redo log后寫binlog的問題
 
  先寫入binlog,后寫入redo log:
 
  寫完binlog之后,所有的語句都被保存,所以通過binlog復制或恢復出來的數據庫中id=2這一行的數據會被更新為a=1。但是如果在redo log寫入之前,系統崩潰,那么redo log中記錄的這個事務會無效,導致實際數據庫中id=2這一行的數據并沒有更新。
 
  先寫binlog后寫redo log的問題
 
  由此可見,兩階段的提交就是為了避免上述的問題,使得binlog和redo log中保存的信息是一致的。
 
  回滾日志(undo log)
 
  回滾日志同樣也是InnoDB引擎提供的日志,顧名思義,回滾日志的作用就是對數據進行回滾。當事務對數據庫進行修改,InnoDB引擎不僅會記錄redo log,還會生成對應的undo log日志;如果事務執行失敗或調用了rollback,導致事務需要回滾,就可以利用undo log中的信息將數據回滾到修改之前的樣子。
 
  但是undo log不redo log不一樣,它屬于邏輯日志。它對SQL語句執行相關的信息進行記錄。當發生回滾時,InnoDB引擎會根據undo log日志中的記錄做與之前相反的工作。比如對于每個數據插入操作(insert),回滾時會執行數據刪除操作(delete);對于每個數據刪除操作(delete),回滾時會執行數據插入操作(insert);對于每個數據更新操作(update),回滾時會執行一個相反的數據更新操作(update),把數據改回去。undo log由兩個作用,一是提供回滾,二是實現MVCC。
 
  三、主從復制
  主從復制的概念很簡單,就是從原來的數據庫復制一個完全一樣的數據庫,原來的數據庫稱作主數據庫,復制的數據庫稱為從數據庫。從數據庫會與主數據庫進行數據同步,保持二者的數據一致性。
 
  主從復制的原理實際上就是通過bin log日志實現的。bin log日志中保存了數據庫中所有SQL語句,通過對bin log日志中SQL的復制,然后再進行語句的執行即可實現從數據庫與主數據庫的同步。
 
  主從復制的過程可見下圖。主從復制的過程主要是靠三個線程進行的,一個運行在主服務器中的發送線程,用于發送binlog日志到從服務器。兩外兩個運行在從服務器上的I/O線程和SQL線程。I/O線程用于讀取主服務器發送過來的binlog日志內容,并拷貝到本地的中繼日志中。SQL線程用于讀取中繼日志中關于數據更新的SQL語句并執行,從而實現主從庫的數據一致。

  到此,相信大家對“MySQL事務日志的特征有哪些”有了更深的了解,不妨來實際操作一番吧!

(編輯:武林網)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 武乡县| 洪湖市| 辽源市| 四会市| 南华县| 溧阳市| 黔西县| 嘉善县| 汉寿县| 蒲城县| 崇信县| 长海县| 逊克县| 嵊泗县| 济宁市| 资兴市| 黑山县| 鹿邑县| 唐山市| 湘乡市| 襄汾县| 株洲市| 玛纳斯县| 广丰县| 祁东县| 裕民县| 都安| 乳源| 古交市| 垣曲县| 宕昌县| 县级市| 集安市| 区。| 屯昌县| 清水县| 枣强县| 墨江| 信阳市| 修武县| 团风县|