MySQL中的undo日志類型使用
1、背景
事務(wù)的回滾機制是通過undo日志來實現(xiàn)的,我們只需要對INSRT、DELETE、UPDATE操作記錄回滾日志,SELECT不需要記錄回滾日志,這三種操作對應(yīng)的undo日志類型不同,接下來就來講一下不同的操作對應(yīng)的不同undo日志類型。
2、事務(wù)id
【1】分配時機
事務(wù)分為只讀事務(wù)和讀寫事務(wù),可以通過START TRANSACTION READ ONLY語句開啟一個只讀事務(wù):
只讀事務(wù)不可用對普通表進(jìn)行插入、刪除、更新操作,但是可以對臨時表進(jìn)行插入、刪除、更新操作,對臨時表進(jìn)行插入、刪除、更新操作時會分配一個唯一事務(wù)id。
可以通過START TRANSACTION READ WRITE、BEGIN、START TRANSACTION語句開啟一個讀寫事務(wù):
讀寫事務(wù)中可以進(jìn)行插入、刪除、更新操作,并且在插入、刪除、更新時會創(chuàng)建一個唯一事務(wù)id。
【2】生成方式
事務(wù)id是服務(wù)器內(nèi)存中的一個唯一全局變量,需要分配事務(wù)id時,就把該變量值加1分配給該事務(wù),當(dāng)該值為256的倍數(shù)時,就將該變量的值存到系統(tǒng)表空間的頁號為5屬性為Max Trx ID占用8個字節(jié)的頁中,當(dāng)服務(wù)器下次重啟時,將該值加上256再賦值給全局變量。
【3】隱藏列
之前講過行的組成包含了隱藏列,由三個字段組成:row_id、trx_id、roll_pointer,這3個字段含義如下:
row_id:不一定存在,如果沒有主鍵和唯一索引才存在。trx_id:此條記錄對應(yīng)的事務(wù)id。roll_pointer:指向最新的undo日志。
3、INSERT操作對應(yīng)的undo日志
【1】TRX_UNDO_INSERT_REC類型
插入一條記錄,我們要將其回滾的話,最主要根據(jù)其主鍵將它刪掉就可以,插入操作對應(yīng)的回滾undo日志類型就為TRX_UNDO_INSERT_REC,其組成結(jié)構(gòu)如下:

字段含義如下:
| 字段 | 含義 |
|---|---|
| end of record | 下一條redo日志 |
| undo type | 日志類型,也就是TRX_UNDO_INSERT_REC |
| undo no | undo日志編號,在事務(wù)中執(zhí)行插入、刪除、更新操作時從0開始遞增 |
| table id | 表唯一id |
| 主鍵列的存儲空間大小和實際值列表 | 主鍵可以由多個列組成,所以這里以一個列表去存儲 |
| start of record | 本條redo日志地址 |
4、DELETE操作對應(yīng)的undo日志
【1】delete mark階段
頁面中的行記錄會根據(jù)記錄頭中的next_record屬性組成單向鏈表,再根據(jù)delete_mask的標(biāo)志是否刪除,細(xì)分成正常記錄鏈表和垃圾鏈表,頁的Page Header有一個PAGE_FREE的屬性,指向垃圾鏈表的頭節(jié)點,當(dāng)我們刪除一條正常記錄時,會先經(jīng)歷delete mark階段:
將正常記錄鏈表中被刪除記錄的delete_mask設(shè)置為1,但不會加入垃圾鏈表,在事務(wù)提交之前一直都在正常記錄鏈表中,只是改變標(biāo)志位。
【2】purge階段
當(dāng)事務(wù)提交之后,就會進(jìn)入purge階段:
后臺會有線程把正常記錄鏈表中被刪除的記錄移動到垃圾鏈表頭節(jié)點處,然后更新頁面中的一些其它屬性:用戶記錄數(shù)量PAGE_N_RECS、上次插入記錄位置PAGE_LAST_INSERT、垃圾鏈表頭節(jié)點指針PAGE_FREE、頁面中可重用的字節(jié)數(shù)量PAGE_GARBAGE等。
【3】TRX_UNDO_DEL_MARK_REC類型
刪除操作對應(yīng)的undo日志類型為TRX_UNDO_DEL_MARK_REC,其結(jié)構(gòu)如下:

字段含義如下:
| 字段 | 含義 |
|---|---|
| end of record | 下一條redo日志地址 |
| undo type | 日志類型,這里是TRX_UNDO_DEL_MARK_REC |
| undo no | undo日志編號 |
| table id | 表id |
| info bits | 記錄頭信息前4個比特位的值以及record_type的值 |
| old trx_id | 該記錄對應(yīng)上一條undo日志的事務(wù)id |
| old roll_pointer | 該記錄對應(yīng)上一條redo日志地址 |
| 主鍵列的存儲空間大小和實際值列表 | 主鍵可以由多個列組成,所以這里以一個列表去存儲 |
| index_col_info len | 索引列信息占用大小 |
| 索引列位置存儲空間大小和實際值列表 | 相比于主鍵信息多了一個位置信息 |
| start of record | 代表本條redo日志 |
5、UPDATE操作對應(yīng)的undo日志
【1】不更新主鍵
不更新主鍵的方式分為就地更新和先刪除舊記錄,再插入新記錄,這兩種更新方式對應(yīng)的undo日志類型都為TRX_UNDO_UPD_EXIST_REC,就地更新指的是:
更新的列更新前后占用的存儲空間都一樣大,就直接在舊記錄上進(jìn)行更新。
先刪除舊記錄,再插入新記錄指的是:
更新的列更新前后有一個列存儲空間發(fā)送變化,就將舊的記錄直接移動到刪除鏈表,然后判斷更新之后的記錄占用的空間小于原來的空間,那就直接重用垃圾鏈表中的空間;否則就在頁面分配一塊新的空間,如果空間不夠,就進(jìn)行頁分裂,再插入新記錄。
TRX_UNDO_UPD_EXIST_REC類型結(jié)構(gòu)如下:

其字段含義如下:
| 字段 | 含義 |
|---|---|
| end of record | 下一條redo日志地址 |
| undo type | 日志類型,這里是TRX_UNDO_UPD_EXIST_REC |
| undo no | undo日志編號 |
| table id | 表id |
| info bits | 記錄頭信息前4個比特位的值以及record_type的值 |
| old trx_id | 該記錄對應(yīng)上一條undo日志的事務(wù)id |
| old roll_pointer | 該記錄對應(yīng)上一條redo日志地址 |
| 主鍵列的存儲空間大小和實際值列表 | 主鍵可以由多個列組成,所以這里以一個列表去存儲 |
| n_updated | 更新列的數(shù)量 |
| 被更新列更新前位置存儲空間實際值列表 | 更新前的列的位置、存儲空間、實際值 |
| index_col_info len | 索引列信息占用大小 |
| 索引列位置存儲空間大小和實際值列表 | 相比于主鍵信息多了一個位置信息 |
| start of record | 代表本條redo日志 |
【2】更新主鍵
更新主鍵的場景會前后產(chǎn)生兩條undo日志,分別為刪除舊記錄對應(yīng)的TRX_UNDO_DEL_MARK_REC類型undo日志和插入新記錄對應(yīng)的TRX_UNDO_INSERT_REC類型undo日志。
6、總結(jié)
本文主要講解了插入、刪除、更新分別對應(yīng)的undo日志結(jié)構(gòu),根據(jù)產(chǎn)生的這些undo日志就能進(jìn)行事務(wù)回滾,具體的回滾方式后面再進(jìn)行講解。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決Navicat for Mysql連接報錯1251的問題(連接失敗)
記得在之前給大家介紹過Navicat for Mysql連接報錯的問題,可能寫的不夠詳細(xì),今天在稍作修改補充下,對Navicat for Mysql連接報錯1251問題感興趣的朋友跟隨小編一起看看吧2021-05-05
Mysql 根據(jù)一個表數(shù)據(jù)更新另一個表的某些字段(sql語句)
這篇文章主要介紹了Mysql 根據(jù)一個表數(shù)據(jù)更新另一個表的某些字段,本文給出了sql語句,感興趣的朋友可以跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05
MySQL重置root密碼提示"Unknown column ‘password"的解決方法
這篇文章主要介紹了MySQL重置root密碼提示"Unknown column ‘password"的解決方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-02-02
mysql 使用inet_aton和inet_ntoa處理ip地址數(shù)據(jù)的實例
下面小編就為大家?guī)硪黄猰ysql 使用inet_aton和inet_ntoa處理ip地址數(shù)據(jù)的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04
Mysql動態(tài)更新數(shù)據(jù)庫腳本的示例講解
今天小編就為大家分享一篇關(guān)于Mysql動態(tài)更新數(shù)據(jù)庫腳本的示例講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12

