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

字段含義如下:
| 字段 | 含義 |
|---|---|
| end of record | 下一條redo日志 |
| undo type | 日志類型,也就是TRX_UNDO_INSERT_REC |
| undo no | undo日志編號(hào),在事務(wù)中執(zhí)行插入、刪除、更新操作時(shí)從0開始遞增 |
| table id | 表唯一id |
| 主鍵列的存儲(chǔ)空間大小和實(shí)際值列表 | 主鍵可以由多個(gè)列組成,所以這里以一個(gè)列表去存儲(chǔ) |
| start of record | 本條redo日志地址 |
4、DELETE操作對(duì)應(yīng)的undo日志
【1】delete mark階段
頁(yè)面中的行記錄會(huì)根據(jù)記錄頭中的next_record屬性組成單向鏈表,再根據(jù)delete_mask的標(biāo)志是否刪除,細(xì)分成正常記錄鏈表和垃圾鏈表,頁(yè)的Page Header有一個(gè)PAGE_FREE的屬性,指向垃圾鏈表的頭節(jié)點(diǎn),當(dāng)我們刪除一條正常記錄時(shí),會(huì)先經(jīng)歷delete mark階段:
將正常記錄鏈表中被刪除記錄的delete_mask設(shè)置為1,但不會(huì)加入垃圾鏈表,在事務(wù)提交之前一直都在正常記錄鏈表中,只是改變標(biāo)志位。
【2】purge階段
當(dāng)事務(wù)提交之后,就會(huì)進(jìn)入purge階段:
后臺(tái)會(huì)有線程把正常記錄鏈表中被刪除的記錄移動(dòng)到垃圾鏈表頭節(jié)點(diǎn)處,然后更新頁(yè)面中的一些其它屬性:用戶記錄數(shù)量PAGE_N_RECS、上次插入記錄位置PAGE_LAST_INSERT、垃圾鏈表頭節(jié)點(diǎn)指針PAGE_FREE、頁(yè)面中可重用的字節(jié)數(shù)量PAGE_GARBAGE等。
【3】TRX_UNDO_DEL_MARK_REC類型
刪除操作對(duì)應(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日志編號(hào) |
| table id | 表id |
| info bits | 記錄頭信息前4個(gè)比特位的值以及record_type的值 |
| old trx_id | 該記錄對(duì)應(yīng)上一條undo日志的事務(wù)id |
| old roll_pointer | 該記錄對(duì)應(yīng)上一條redo日志地址 |
| 主鍵列的存儲(chǔ)空間大小和實(shí)際值列表 | 主鍵可以由多個(gè)列組成,所以這里以一個(gè)列表去存儲(chǔ) |
| index_col_info len | 索引列信息占用大小 |
| 索引列位置存儲(chǔ)空間大小和實(shí)際值列表 | 相比于主鍵信息多了一個(gè)位置信息 |
| start of record | 代表本條redo日志 |
5、UPDATE操作對(duì)應(yīng)的undo日志
【1】不更新主鍵
不更新主鍵的方式分為就地更新和先刪除舊記錄,再插入新記錄,這兩種更新方式對(duì)應(yīng)的undo日志類型都為TRX_UNDO_UPD_EXIST_REC,就地更新指的是:
更新的列更新前后占用的存儲(chǔ)空間都一樣大,就直接在舊記錄上進(jìn)行更新。
先刪除舊記錄,再插入新記錄指的是:
更新的列更新前后有一個(gè)列存儲(chǔ)空間發(fā)送變化,就將舊的記錄直接移動(dòng)到刪除鏈表,然后判斷更新之后的記錄占用的空間小于原來的空間,那就直接重用垃圾鏈表中的空間;否則就在頁(yè)面分配一塊新的空間,如果空間不夠,就進(jìn)行頁(yè)分裂,再插入新記錄。
TRX_UNDO_UPD_EXIST_REC類型結(jié)構(gòu)如下:

其字段含義如下:
| 字段 | 含義 |
|---|---|
| end of record | 下一條redo日志地址 |
| undo type | 日志類型,這里是TRX_UNDO_UPD_EXIST_REC |
| undo no | undo日志編號(hào) |
| table id | 表id |
| info bits | 記錄頭信息前4個(gè)比特位的值以及record_type的值 |
| old trx_id | 該記錄對(duì)應(yīng)上一條undo日志的事務(wù)id |
| old roll_pointer | 該記錄對(duì)應(yīng)上一條redo日志地址 |
| 主鍵列的存儲(chǔ)空間大小和實(shí)際值列表 | 主鍵可以由多個(gè)列組成,所以這里以一個(gè)列表去存儲(chǔ) |
| n_updated | 更新列的數(shù)量 |
| 被更新列更新前位置存儲(chǔ)空間實(shí)際值列表 | 更新前的列的位置、存儲(chǔ)空間、實(shí)際值 |
| index_col_info len | 索引列信息占用大小 |
| 索引列位置存儲(chǔ)空間大小和實(shí)際值列表 | 相比于主鍵信息多了一個(gè)位置信息 |
| start of record | 代表本條redo日志 |
【2】更新主鍵
更新主鍵的場(chǎng)景會(huì)前后產(chǎn)生兩條undo日志,分別為刪除舊記錄對(duì)應(yīng)的TRX_UNDO_DEL_MARK_REC類型undo日志和插入新記錄對(duì)應(yīng)的TRX_UNDO_INSERT_REC類型undo日志。
6、總結(jié)
本文主要講解了插入、刪除、更新分別對(duì)應(yīng)的undo日志結(jié)構(gòu),根據(jù)產(chǎn)生的這些undo日志就能進(jìn)行事務(wù)回滾,具體的回滾方式后面再進(jìn)行講解。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Mysql實(shí)現(xiàn)null值排在最前/最后的方法示例
這篇文章主要給大家介紹了關(guān)于Mysql實(shí)現(xiàn)null值排在最前/最后的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
MySQL 實(shí)現(xiàn)lastInfdexOf的功能案例
這篇文章主要介紹了MySQL 實(shí)現(xiàn)lastInfdexOf的功能案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12
MySql索引原理之聯(lián)合索引與最左前綴原則、覆蓋索引及索引條件下推詳解
本文給大家介紹InnoDB索引機(jī)制,包括聯(lián)合索引的最左前綴原則、覆蓋索引優(yōu)化、索引條件下推(ICP)功能及索引失效場(chǎng)景,強(qiáng)調(diào)合理設(shè)計(jì)索引可提升查詢效率,避免全表掃描,對(duì)mysql最左前綴原則相關(guān)知識(shí)感興趣的朋友一起看看吧2025-08-08

