MySQL中事務:
- 事務的實現:
ACID:
-
- 原子性(A : Atomicity)
- 一致性(C : consistency )
- 隔離性(I : isolation)
- 持久性(D : durability )
- 實現方式:
-
- 隔離性:通過鎖來實現
- 原子性和持久性:通過redo log 來實現
- 一致性:通過undo來實現
- redo 和 undo 比較:
都是恢復操作:
-
- redo:恢復提交事務修改的頁操作
- undo: 回滾行記錄到某個特定版本
記錄內容不同:
-
- redo: 是物理日志,記錄的是物理的修改操作
- undo: 是邏輯日志,根據每行記錄進行記錄
讀取方式不同:
-
- redo : 在數據庫運行時,不需要讀取操作(注:數據庫恢復時,才用redo)
- undo : 在數據庫運行時,需要隨機讀取(注:回滾時用)
redo-在事務中的應用
1.基本概念
【事務持久性:D】-- 【重做日志來實現】
【持久性構成】:1.重做日志緩沖(redo log buffer) ,是易失的 2.重做日志文件(redo log file),是持久的
【持久性原理】:InnoDB是事務的存儲引擎,通過Flush Log at Commit機制實現事務的持久性。即:當事務提交(Commit)時,必須先將事務的所有日志(這里只重做日志)寫入到重做日志文件中,進行持久化,待事務的commit完成才算完成。
【事務的所有日志】:在InnoDB中,事務的所有日志有兩部分:redo log 和 undo log
【fsync操作】:為了確保每次重做日志都寫入重做日志文件,在將重做日志緩沖寫入重做日志文件后,InnoDB存儲引擎都需要調用一次fsync操作。
【innodb_flush_method = O_DIRECT/NULL】: 控制InnoDB數據文件和redo log 文件打開,刷寫模式。
1.設置為NULL時,默認是:fsync選項。過程:重做日志緩沖先寫入文件系統緩存,再進行fsync(將日志刷新到重做日志文件 )操作。依賴磁盤的性能。
2.設置為O_DIRECT,過程:調用用O_DIRECT打開數據文件, 然后調用:fsync(),將所有刷新到數據和log文件中。不經過操作系統緩存,
避免兩次寫操作。
【非持久性】:通過手工設置非持久性來提高數據庫性能。
原理:事務提交時,日志不寫入重做日志文件,而是等待一個周期后,再執行fsync操作。不是強制每次提交都fsync,可以顯著提高性能。
弊端:如果數據庫發生宕機,由於部分日志未刷新到磁盤,會丟失最后一段的事務。
【innodb_flush_log_at_trx_commit = 0/1/2】:該參數控制重做日志刷新到磁盤的策略。
1 : 默認是1,表示事務提交時必須調用一次fsync,<redo log刷新條件之一:事務提交前必刷新到日志文件>。
遵循ACID的持久性。
0 : 事務提交時,不進行寫重做日志操作.寫的操作僅在master Thread中完<redo log 刷新條件之二>,大概每隔1秒執行一次fsync操作.
在1秒內有數據庫宕機丟數據的風險.
2 : 寫重做日志文件,但僅僅寫入文件系統緩存中,不進行fsync操作。僅數據庫宕機系統正常,不會丟數據。 系統宕機,緩存中未刷新到重做日志文件的那部分事務會丟失.
總結:0和2能提高事務提交性能,但是這種情況喪失了事務的ACID特性,因此在大量執行insert操作時,在最后執行一次commit操作。這樣回滾時可以回滾到事務最開始的狀態.
Innodb存儲引擎使用中,為了遵循持久性和一致性,關於復制的設置:
1.如果啟用二進制日志(binlog),設置: sync_binlog=1;
2.同時也設置:
innodb_flush_log_at_trx_commit=1.
【sync_binlog = N】:
N=0,事務提交后,不做fsync之類的磁盤同步指令,刷新binlog_cache到磁盤文件,而是讓文件系統自行決定什么時間同步。
性能高,但是有丟失數據的風險.
N=1,1次事務提交后,執行fsync操作,將binlog chace同步到磁盤文件。這
種選擇是最安全的,但是是最慢的.
【binlog和redo log比較】:
1.產生層面不同
redo log: 是在存儲引擎層產生,只針對InnoDB存儲引擎
binlog:在數據庫上層產生的.MySQL中任何存儲引擎對數據庫的更改都會產生二進制日志.
2.記錄內容形式不同
redo log: 是物理格式的日志,記錄的是對於每個頁的修改.
binlog: 是一種邏輯日志,記錄的是sql語句.
3.寫入磁盤時間不同
redo log: 在事務進行中不斷的寫入.不隨事務的提交而提交,不是順序寫入的.
binlog: 在事務提交后進行寫入.
2.日志塊的結構
在InnoDB存儲引擎中,重做日志都是以512字節進行存儲的.也就是說重做日志緩沖,重做日志文件都是以塊(block)的方式進行保存.稱為:重做日志塊(redo log block),大小:512字節.
如果一個頁中產生的重做日志大於512字節,就分割成多個重做日志塊就行存儲.
重做日志塊的大小和磁盤扇區的大小一樣,512字節,因此重做日志的寫入
可以保證原子性,
不需要doublewrite技術.
日志塊的組成:日志本身,日志塊頭(log block header),日志塊尾(log block tailer)

Log Block Header 解析:
LOG_BLOCK_HDR_NO:4字節
log buffer由log block組成,在內部就像一個數組,而LOG_BLOCK_HDR_NO,用來標記這個數組中的位置。改制必須大於0,允許最大2G;如果在日志刷新寫入段時,是第一個日志塊,最高位就設置成1.
LOG_BLOCK_DATA_LEN:2字節
表示LOG_BLOCK所占用的大小,被寫滿時,該值為:0x200,表示全部block空間,即占用512字節。
LOG_BLOCK_FIRST_REC_GROUP:占用2字節
表示LOG_BLOCK中第一個日志所在的偏移量。如果LOG_BLOCK_FIRST_REC_GROUP=LOG_BLOCK_DATA_LEN 表示log block不包含新的日志。
LOG_BLOCK_CHECKPOINT_NO:4字節
表示:LOG_BLOCK最后被寫入時的檢查點。如果此時log block還沒寫滿,只能等下次log flush 時,才會更新。
關於一個事務占用兩個log block的圖:
事務T1的重做日志占用:696字節
事務T2的重做日志占用:100字節

有圖知道:事務T1 696字節,占用兩個log block,左側的log block中 LOG_BLOCK_FIRST_REC_GROUP=12,即第一個日志開始的位置。
在第二個block中,由於包含了T1的重做日志,因此事務T2的重做日志才是block中的第一個日志,即 LOG_BLOCK_FIRST_REC_GROUP=(12+200)=212
3.重做日志組(log group)
log group為重做日志組,里面有多個重做日志文件。源碼中支持log group的鏡像功能,但已禁用了,因此InnoDB存儲引擎實際只有1個log group。
log group 是邏輯上的概念!!!
重做日志存儲的就是之前在log buffer中保存的塊,因此也是根據塊的方式進行物理存儲的管理。block=512bytes。
InnoDB存儲引擎運行過程中, log buffer根據一定的規則將log block刷新到磁盤:
1.事務提交時
2.當log buffer中一半的空間已經被使用
3.log checkpoint時
redo log file的寫入順序:
log block 寫入追加到redo log file的最后部分,當一個redo log file寫滿時,會寫入下一個redo log file。 這種方式:round-robin.
看起來是順序的,其實不然,除了保存log buffer刷新到磁盤的log block,還保存了一些其他信息,這些信息占:2KB,即redo log file 的前2KB不保存log block的信息。
2KB的信息:保存 4 * 512字節的 塊。
名稱 |
大小(字節)
|
log file header
|
512
|
checkpoint1
|
512
|
空
|
512
|
checkpoint2
|
512
|
上述信息只在log group的第一個redo log file里存儲,其余file留空,這也就是說 寫入不是順序的!如下圖:

4.重做日志的格式

5.LSN
LSN : Log Sequence Number的縮寫,代表日志序列號,單位:字節。在innodb存儲引擎中占有8字節,單調遞增。
LSN : 表示的含義
- 重做日志寫入的總量
- checkpoint的位置
- 頁的版本
LSN 表示事務寫入重做日志的字節總量。例如,當前重做日志的LSN是1000,事務T1寫入了100字節的重做日志,LSN就變成1100,又有事務T2寫入200字節的重做日志,那么LSN變成:1300.
LSN不僅記錄在重做日志中,還記錄在頁中。每個頁的開頭部有一個FIL_PAGE_LNS,記錄該頁的LSN。
頁中的LSN表示:該頁最后刷新時LSN的大小。
重做日志記錄的是每個頁的物理更改日志,因此頁中的LSN用來判斷是否需要進行恢復操作。例如:頁的LSN為:10000,數據庫啟動時,寫入重做日志的LSN:13000,表明該事務已經提交,數據庫需要恢復;重做日志中的LSN小於頁中的LSN,不需要進行重做,因為頁中的LSN表示已經刷新到該位置。
通過:SHOW ENGINE INNODB STATUS\G來查看LSN的情況
---
LOG
---
Log sequence number 47324552 ----------------->表示當前的LSN
Log flushed up to 47324552 ----------------->表示刷新到重做日志的LSN
Pages flushed up to 47324552 ----------------->表示刷新到磁盤的LSN
Last checkpoint at 47324552
Max checkpoint age 80826164
Checkpoint age target 78300347
....
上述的3個值,生產環境中可能是不同的:因為一個事務從重做日志緩沖刷新到重做日志文件,並不只是在事務提交時發生,每秒都會有重做日志緩沖刷新到重做日志文件的操作。
6.恢復
InnoDB存儲引擎在啟動時,不管上次數據庫是否正常關閉,都會嘗試進行恢復。重做日志是物理日志,恢復時比較快。
checkpoint 表示已經刷新到磁盤上的LSN。
例子:redo log file 記錄的LSN:13000,刷新到磁盤上的LSN:10000,數據庫在10000處宕機,恢復時,只需恢復10000~13000的部分。

--完結