mysql【週五】day12

課程回顧:
1、存儲引擎介紹
介紹:類似於linux的文件系統
種類:(show engine) innodb(5.7版本用戶表全是innodb)、myisam(5.7mysql下有些系統表還是myisam引擎)、CSV、memory
tockdb (壓縮比例高、insert高、zabbix歸檔庫、歷史庫、日誌庫)

innodb核心特性:
1、事務
2、MVCC
3、啓動故障恢復(CR)
4、行級鎖
5、熱備
6、多緩衝區(IBP)ILB等
7、雙寫機制(Double write)
8、聚簇索引
9、AHI自適應HASH
10、change buffer
myisam 表級鎖 溫備份

2、innodb 引擎管理
查看(show create table; information_schema.tables)
設置 my.cnf ;create table ; alter table t1 engine=innodb;

3、innodb案例
innodb替換爲tockdb案例
myisam提換爲innodb
碎片整理
4、體系結構
on-disk
1、表空間 system tablespace;file_per_table table2、日誌 3、其他部分
in-memory
1、IBP 2、ILB

在這裏插入圖片描述

事務的生命週期管理
標準的事務控制語句
開啓事務
begin ;start transaction;
提交事務
commit;
回滾事務
rollback

事務生命週期中只能使用DML語句(select update delete insert)

在這裏插入圖片描述

mysql的自動提交機制 (auto_commit)
參數:

mysql> select  @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)

作用:

在沒有顯示的使用begin語句的時候,執行DML,會在DML自動添加begin 並在DML執行後自動添加commit。

每提交一次就一次IO刷盤
建議:頻繁事務業務場景中,建議關閉autocommit。減少磁盤IO。或者是每次事務工作時,都顯示begin和commit

設置autocommit 的參數方法:
臨時方法:

mysql> set global autocommit=0;
mysql> select  @@autocommit;

vim /etc/my.cnf

autocommit=0

0爲關閉 (關閉後你的操作執行完成後需要手動輸入commit操作)
1爲開啓(開啓後直接輸入語句就可以了,自動數據commit)
所以說 頻繁業務時,爲了減少IO的次數,建議多條語句一同執行減少IO次數。
這種情況下 建議設置爲0

隱式提交和回滾
隱式提交情景

6.3.3 隱式提交和回滾 
# 隱式提交情況 
begin 
a
b
begin

SET AUTOCOMMIT = 1
導致提交的非事務語句:
DDL語句: (ALTER、CREATE 和 DROP)
DCL語句: (GRANT、REVOKE 和 SET PASSWORD)
鎖定語句:(LOCK TABLES 和 UNLOCK TABLES)
導致隱式提交的語句示例:
TRUNCATE TABLE
LOAD DATA INFILE
SELECT FOR UPDATE

# 隱式回滾 
會話窗口被關閉。
數據庫關閉 。
出現事務衝突(死鎖)。

注意:在事務中支持DML 不要使用DDL DCL 等操作,只進行DML操作

事務的隔離級別
作用:實現事務工作期間的讀的隔離
讀 物理層的讀-----mysql數據頁的讀取(說的是將數據從磁盤上讀取到內存中的讀,不是邏輯SQL語句的讀)
==並不是邏輯層的select ==

隔離級別類型
mysql> select @@transaction_isolation;

四種模式:
RU read-uncommited 讀未提交模式
可以讀取到事務未提交的數據。隔離性不高。髒讀(當前內存讀)不可重複讀 、幻讀
RC read-commit 讀已提交模式 (可以用)
可以讀取到事務已經提交的問題 隔離性一般,可以避免髒讀, 不可重複讀,幻讀問題不可避免
RR repeatable-read 可重複讀 (默認)

SR serializable 可串行化

出現的我認爲的奇異現象

在這裏插入圖片描述
一個begin修改後commit 一個是begin 修改後沒有commit 所以出現的這個情況
想要統一,兩個begin最後都要進行commit纔可以。

實驗的步驟:
實驗前提:autocommit=0 關閉自動提交

在這裏插入圖片描述

配置文件

[root@db01 ~]# cat /etc/my.cnf
[mysqld]
user=mysql
basedir=/data/app/mysql
#basedir=/data/app/mysql56
datadir=/data/3306/data
socket=/tmp/mysql.sock
character_set_server=utf8mb4
general_log=on
secure-file-priv=/tmp
#default_storage_engine=myisam
#innodb_data_file_path=ibdata1:12M;ibdata2:100M;ibdata3:100M:autoextend
innodb_data_file_path=ibdata1:100M;ibdata2:100M;ibdata3:100M:autoextend
innodb_undo_tablespaces=3           
innodb_max_undo_log_size=128M
innodb_undo_log_truncate=ON
innodb_purge_rseg_truncate_frequency=32
innodb_temp_data_file_path=ibtmp1:12M;ibtmp2:128M:autoextend:max:500M
innodb_log_file_size=100M
innodb_log_files_in_group=3
innodb_buffer_pool_size=256M
innodb_log_buffer_size=33554432
autocommit=0
##transaction_isolation=READ-UNCOMMITTED
##transaction_isolation=READ-COMMITTED
[mysql]
socket=/tmp/mysql.sock
#pager=less

事務工作流程(ACID特性如何保證)
名詞解釋:
1、重做日誌redo log
ib_logfile0~n 48M 輪詢使用
2、redo log buffer 日誌緩衝區: redo內存區域
3、ibd 表空間數據文件:存儲數據行和索引
4、innodb buffer pool 緩衝區池 數據和索引的緩衝
5、LSN 日誌序列號 版本控制軟件
磁盤數據頁(ibd文件的page) redo文件(ib_logfile) 、buffer pool (innodb_bufferpool中的數據頁)、 redo buffer(日誌緩衝區中的版本號)

redo buffer > redo 文件  > innodb_buffer_pool 中的數據頁>磁盤

mysql 每次數據庫啓動,都會比較磁盤數據頁和redo log的LSN,必須要求兩者LSN一致數據庫才能正常啓動。
6、WAL:write ahead log redo 日誌優先於數據頁寫
7、髒頁:dirty page
內存髒頁,內存中發生了修改,沒寫入磁盤之前,我們把內存頁稱之爲髒頁
8、checkpoint
CKPT:檢查點,就是將髒頁刷新到磁盤的動作
9、DB_TRX_ID(6字節) 事務ID號
事務號 innodb 會爲每一個事務生成一個事務號,伴隨整個事務的生命週期。
10、DB_ROLL_PTR (7字節) 回滾指針
rollback時,會使用undo 日誌回滾已修改的數據。DB_ROLL_PTR指向了此次事務的回滾位置點,用來找到undo日誌信息

innodb事務處理流程圖

在這裏插入圖片描述

日誌先寫入到iblog 然後數據再CKPT寫入磁盤
宕機的話,使用iblog 進行LSN對比,重新讀取到內存,然後使用CKPT寫回到磁盤
不宕機的話,怎麼寫入磁盤?是使用CRT

流程:SQL語句執行-------ibd表中調取數據頁------buffer_pool(加載到內存)-----log_buffer(記錄page修改的變化)-----修改的日誌保存在ib_logfile -----CKRT寫數據從內存到磁盤(正常情況已經完成了)

流程:SQL語句執行-------ibd表中調取數據頁------buffer_pool(加載到內存)-----log_buffer(記錄page修改的變化)-----修改的日誌保存在ib_logfile -----CKRT寫數據從內存到磁盤(正常情況已經完成了)

宕機情況出現時:
宕機恢復後,自動檢查LSN號碼,會比較磁盤數據頁和redolog的LSN(lsn號碼記錄數據頁字節發生量,記錄日誌字節發生量),必須要求兩者LSN一致數據庫才能正常啓動,於是將redolog加載到log_buffer,將原始的數據頁重新加載到buffer_pool,,在緩衝區實現LSN重新同步

如果LSN和redo log中的LSN號碼一致 就可以覆蓋掉該LSN號碼了,使得ib_logfile1 的存儲空間是夠用的

事務舉例:

begin;
update  t1 set a=2 where a=1;
commit;

redo log 重做日誌如何應用
1、用戶發起update事務語句,將磁盤數據頁(page100,A=1,LSN=1000)加載到內存(buffer_pool)緩衝
2、在內存中發生數據頁修改(A=1改成A=2),形成髒頁,更改中數據頁的變化會被記錄到redo buffer中,1000個字節日誌。LSN號碼=1000+1000=2000
3、當commit語句執行時,基於WAL機制,等到redo_buffer中的日誌完全落盤到ib_logileN中,commit正式完成。
4、此時ib_logfileN中記錄了一條日誌。內容:page100數據頁變化+LSN=2000號碼

當此時,如果redo 落盤了,但數據頁沒有落盤------宕機了
1、mysql CR (自動故障恢復)工作模式,啓動數據庫時,自動檢查redo的LSN和數據頁的LSN。
2、如果發redo的LSN號碼大於數據頁的LSN,會觸發實例恢復過程(加載原始數據頁+變化redo加載到指定內存區域。使用redo重構髒頁,我們稱爲前滾)
3、如果此時事務已經提交(commit標籤),立即觸發CKPT動作將髒頁刷盤
如果沒提交commit的話,會觸發回滾機制

補充一點:
mysql中有一種機制,redo group commit機制,也是批量刷寫redo的機制。會在A事務commit時,順便將redo buffer中未提交的redo日誌也一併刷寫到磁盤。
爲了區分不同狀態的redo,日誌記錄時會標記是否commit。

疑問:
那他打不打這個commit標籤有啥用?

這裏講的事務工作流程原理是宕機異常時 用到redo log日誌的
如果沒有問題,那就按照CKPT方式
不能直接複製ibd_file0的東西,因爲LSN號碼不匹配,無法打開的

redo保證了哪些ACID特性?
主要是D 另外A、C也有保證
主要是 持久性 和原子性和一致性也有間接關係

undo是邏輯日誌信息(redo是物理日誌信息)
在語句執行之前就記錄在undo之中,然後再寫入到內存的數據頁頭部,行成髒頁

undo log日誌原理

在這裏插入圖片描述

undo log回滾日誌如何應用
1、事務發生數據頁修改之前,會申請一個undo事務操作,保存事務回滾日誌(逆向操作的邏輯日誌)
2、undo寫完落地之後 事務會記錄數據頁頭部 會記錄(DB_ID+DB_ROLL_PTR)事務ID和指針號 ,這個信息也會被記錄到redo中
情景一:
當用戶進行rollback動作觸發時,根據數據頁的事務ID和指針號信息,找到undo日誌,進行回滾
(已經在內存中修改的數據頁找到在undo記錄的語句,進行回滾。)

情景二:
假設:undo 有 ;redo沒有;
啓動數據庫時檢查redo和數據頁的LSN號碼,發現是一致的。所以不需要redo的前滾,此時也不需要回滾。undo信息直接被標記爲可被覆蓋狀態。

假設:undo 有,redo也有(沒有commit標籤。)

  1. MySQL CR(自動故障恢復)工作模式,啓動數據庫時,自動檢查redo的LSN和數據頁LSN。
  2. 如果發現redoLSN>數據頁的LSN ,加載原始數據頁+變化redo指定內存。使用redo重構髒頁(前滾)。
  3. 如果確認此次事務沒有commit標記,立即觸發回滾操作,根據DB_TRX_ID+DB_ROLL_PTR信息,找到und回滾日誌,實現回滾。
    以上流程被稱之爲InnoDB的核心特性:自動故障恢復(Crash Recovery)。先前滾再回滾,先應用redo再應用undo。

commit標記是根據 commit命令執行,提交了後redo就有commit標記,沒提交就沒有,,commit執行成功,唯一能保證的是redo落盤。數據不一定落盤,, 數據頁落盤是buffer pool滿了或是redo 日誌滿了就會立刻羅盤 默認 buffer pool 達到 75時。到達75時候 觸發CKPT

undo在ACID保證什麼
主要是保證了 A 原子性 (全成功或者全失敗)
同時保證了C和I特性 一致性、隔離性

C特性 事務的一致性 主要是誰保證的
CR 和double write 保證的
CR:數據庫以外宕機時刻通過redo前滾和undo回滾 保證數據的最終一致
double write:5.7中默認存儲在ibdataN中。解決數據寫入不完整。

在這裏插入圖片描述

如果沒有DW會直接寫入到數據頁中,如果寫一般宕機了,會導致block損壞,導致數據頁壞了,使用undo和redo也無法恢復。
所以加入了一個流文件,先寫到double write再寫到數據頁。就可以避免這個問題。
每次1M,分兩次寫入DWB中

在Innodb將數據頁寫到數據存儲文件之前,存儲從Innodb緩存池刷過來的數據頁。且只有將數寫入doublewriter buffer後,Innodb纔會進行數據頁的物理存儲。如果在數據頁寫盤時發生操作系統、存儲系統、或者myql進程中斷,Innodb可以從doublewriter buffer存儲中找回丟失的數據頁備份

double write的工作原理:使用double write做此次寫入數據的副本
在這裏插入圖片描述

buffer pool是按照數據頁的方式進行傳入到ibd 每個數據頁是16kb ;先寫入double write 可以保證每個16KB出現錯誤,這個數據頁不會出現損壞磁盤。

宕機的時候,如果數據頁不完整,redo不能恢復,這時候dw就相當於一個引子,之後再進行前滾,回滾,髒頁cheakpoint之類的操作。double write 是一個副本。

事務中I的特性怎麼保證?
隔離性
隔離級別: 讀隔離性
RU 髒讀 、不可重複讀、幻讀 隔離級別最差
RC *** 不可重複讀 幻讀
RR *** 有可能出現 幻讀
SR 事務串行化處理,但是不適合並行處理,併發性太低

鎖機制:寫的隔離,修改的隔離
作用:保護併發訪問資源
保護的資源分類:
內存資源分類:
latch rwlock、mutex 主要保護內存資源

先1M速率從BP 2次寫入DW,,寫滿DW然後 從BP往IBD寫 寫入的總量也是2M 寫完後 然後下一次再1M速率從BP 2次寫入DW,覆蓋上一次的2M,,寫滿DW然後 從BP往IBD寫 寫入的總量也是2M ,,這樣每次從BP往IBD寫之前,,都提前先備份了這要寫入的2M到DW中,,因此能保證宕機之後通過DW修復IBD

一個數據頁 16K 單位數據頁如果落盤不完整 ,纔算原數據損壞 髒頁完整數據量沒完全落盤不算損壞 所以DW大小2M完全可以保證 一次傳輸量的數據頁的修復 DW也存在磁盤上
在這裏插入圖片描述

事務中的I的特性怎麼保證?
隔離級別:讀隔離性
RU : 髒讀 、 不可重複讀 、幻讀
RC : 不可重複讀、幻讀
RR :有可能會出現幻讀。
SR :事務串行工作。

鎖機制:寫的隔離
作用:保護併發訪問資源。
保護的資源分類:
latch:rwlock、mutex,主要保護內存資源
MDL: 元數據
tablelock: 表級別
row lock:
record lock
gap lock
next lock
功能性上:
IS
S
IX
X

MVCCC : 多版本併發控制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章