天天看點

關于MySQL事務的簡單講解

事務:

mysql要開始一個事務需要begin

扁平事務 不能送出或者復原一部分,最常見的一種事務

三種結果 主動送出 (遇到錯誤)主動復原  被動復原 

帶有儲存點的扁平事務可以復原一部分,儲存點僅僅是一個标簽,事務沒送出前,一旦資料庫崩潰,事務全部復原,不會因為儲存點而部分復原

鍊事務(基本不用):應用于 一個大事務分多次送出, (送出釋放鎖資源),但是一個大事務多次送出缺不能回復原

嵌套事務(mysql不支援嵌套事務 oracle支援):由若幹個事務組成, 中間的部分事務送出 隻要總的復原,那麼裡面的事務也都會復原

分布式事務:

核心是 一個事務跨兩個資料庫  

當一個事務跨兩個資料庫并且需要獨自送出,這時候需要使用分布式事務 可以保證兩事務同時送出或者復原

但是mysql支援的分布式事務并不好                                                                                                    

對于innodb支援 扁平 帶有儲存點的扁平 鍊事務 分布式事務

對于mysql資料庫來講無論是事務還是sql都要盡可能的簡單 。為了減少mysql中的分布式事務等複雜事務我們可以在程式層面控制,将不同的商品放在不同的資料庫中,避免一個事務同時通路兩台資料庫

對事務的實作必須要有redo 和undo

redo log 作用:

保證事務的持久性,

支援緩沖寫

崩潰恢複(前滾恢複速度快,速度穩定,(速度主要取決于io))

redo 分為 兩部分: 記憶體: redo log buffer

                   磁盤: redo log file

redo記錄方式:

實體日志的記錄方式(對某檔案某個頁所做的操作),不需要解析,

因為實體日志寫的單元是512位元組,是以不需要double write

redo保證了事務的持久性:

  原因:

日志先行

1、當事務送出的時候,會将redo log buffer中的日志寫入到磁盤

2、當log buffer大小占用1/2的時候,會往磁盤裡重新整理

3、 資料寫入磁盤的時候會觸發檢查點  log chechkpoint

所謂的檢查點我們可以認為:

系統恢複的最早的那個點即寫入到磁盤的最新髒塊的redo log的位置(被記錄到ibdata中即最早髒的那個資料塊 系統崩潰恢複的時候,檢查點作為崩潰恢複檢查的起點)

redo 由兩部分組成: redo log buffer 、 redo log file(差別與bin log)

通過 innodb_flush_log_at_trx_commit參數來控制寫入重做日志的級别;預設值是1 

0:日志緩沖每秒一次地被寫到日志檔案,并且對日志檔案做到磁盤操作的重新整理,但是在一個事務送出不做任何操作。

1:在每個事務送出時,日志緩沖被寫到日志檔案,對日志檔案做到磁盤操作的重新整理。

2:在每個送出,日志緩沖被寫到檔案,但不對日志檔案做到磁盤操作的重新整理。對日志檔案每秒重新整理一次。網易技術部 67

預設值是 1,也是最安全的設定,即每個事務送出的時候都會從 log buffer 寫到日志檔案,而且會實際重新整理磁盤,但是這樣性能有一定的損失。

如果可以容忍在資料庫崩潰的時候損失一部分資料,那麼設定成 0 或者 2 都會有所改善。設定成 0,則在資料庫崩潰的時候會丢失那些沒有被寫入日志檔案的事務,最多丢失 1 秒鐘的事務,

種方式是最不安全的,也是效率最高的。設定成 2 的時候,因為隻是沒有重新整理到磁盤,但是已經寫入日志檔案,是以隻要作業系統沒有崩潰,那麼并沒有丢失資料 ,比設定成 0 更安全一些。

當我們批量導資料的時候可以将該參數改為0  (50w個insert 事務,設為1需要50秒,設為0僅需要13秒就可以完成)

redo  特點: 順序寫,在資料庫正常運作情況下我們不去讀髒塊:

事務已經送出,redo log一定已經寫入了磁盤

事務沒有送出,髒塊已經寫入到了磁盤,redo log 一定寫入到了磁盤

這個事務沒有送出,是以復原的資料一直存在,這個復原的資料被redo log保護,,保證崩潰恢複的時候undo的正确復原

事務沒有送出,redo log也沒有寫入磁盤

innodb_log_group_home_dir,最好将redo放在寫性能很高的磁盤 如ssd

innodb_log_file_in_group  設定redo file的每組多少個 建議設定5個,設定過低,當切換redo的時候,資料庫會出出現短暫的停頓,。

保護了redo log就是保護了事務(redo log的保護比資料檔案的保護還要重要)

binlog : 備份恢複, 主從複制   redo log 隻對innodb引擎有效,bin log 對innodb 和 myism引擎都有效

redo log是基于頁的實體記錄方式即記錄着該資料對應的頁 行的位址,恢複的時候指定在哪恢複

bin log 邏輯層面 是基于語句級的記錄方式

lsn号; 每條日志,每個資料頁

每一個資料頁,每一條日志都有lsn号 檢查點也有lsn号  lsn号記錄的就是資料的位置

double write技術

redo lock

log group

mysql中,組之間是鏡像關系

redo 的日志格式:

redo_log_type 重做日志的類型

space 表空間的id     

page_no 頁的偏移量

redo_log_body具體的操作格式

undo主要的三個作用:

1、事務復原    

2、mvcc    

3、崩潰恢複

ibdata 共享表空間裡第五個頁是屬于 undo的預設128個段

128個段各自又有多個塊,

每個段的第一個塊成為段頭塊

uodo的第一個塊被稱為系統事務表,分别指向不同段的段頭塊

段頭塊:

一個段頭塊最多可以有1024的slot(可以認為每個段最多可以有1024個事務,即一個資料庫最多可以并發128*1024個事務)

一個事務的起始、

事務開始是會生成一個事務id:xid(依次遞增),在系統事務表裡找到一個相對空閑(活躍事務較少的段)的undo段,将自己的xid寫進段頭塊的一個空閑槽位slot,事務修改資料前,将資料存放到空閑的塊中,需要多個塊的時候,位址依次相連(undo塊使用了鍊條進行連結),最後一個用到的塊會指向段頭塊的那個槽位

commit: 修改slow 已送出

rollback:

事務沒有被送出,slot不會被覆寫,undo塊不會被覆寫

找到最後一個塊,依次往前復原

是以如果是一個大事務,復原時間會很長

崩潰恢複,復原完,開始前滾,記錄了事務的最大id,那說明所有未送出的事務都小于該id

但是并不會馬上復原,當新的事務修改資料塊時,發現該資料塊的事務未送出,就會前去復原

事務送出但是沒被寫入磁盤需要redo 前滾,有些事務沒送出但是被寫入磁盤則需要undo復原

undo 段 預設128個 

undo頁需要回收。 通過purge線程 

同時支援的活動事務的數量 =undo段數*1024

可以用py_innodb_page_info.py工具來檢視目前共享表空間的undo的數量

history list: 

按照事務送出的順序将已送出的事務連起來,(這些事務也都分别對應着自己的undo塊),當我們在purge清空回收undo塊的時候,會根據history list 的順序從尾端依次清空,即先清空事務最早的送出的undo塊

關于MySQL事務的簡單講解

show engine innodb status 在transactions中可以監控到history list的長度,當這個長度增長較快的時候

說明資料庫undo的重新整理可能出現了問題這時可以考慮是否有大量的未送出的事務

表示該資料庫的undo已經重新整理到了1793,這個事務id, 也就是比這個事務id還小的事務都已經執行

關于MySQL事務的簡單講解

通過以下參數來控制undo

innodb_undo_directory :可以設定undo段檔案所在的路徑(預設在預設表空間裡可以通過修改路徑将其放在單獨的檔案中)

innodb_undo_logs : 設定復原段的個數(最大值就是128)

innodb_undo_tablespaces  :用來設定構成undo段的檔案的數量,即将undo段配置設定到多個檔案裡因為下面已經設定了多個raid是以該參數沒喲多大意義

關于記憶體中undo 頁的回收即purge 是一個磁盤離散讀取的過程消耗io為了節約undo采用了重用模式,即一個undo頁如果備用空間小于3/4那麼其他的事務也可以将undo資料存放到該頁上節約undo的占用空間

關于事務控制: auto_commit自動送出的原因是 mysql在解決鎖的問題上壓力很大