書名: 深入理解MySQL主從原理作者名: 高鵬本章字數: 8字更新時間: 2021-04-16 16:29:31
2.5 重點Event之WRITE_EVENT和DELETE_EVENT
2.5.1 WRITE_EVENT
1.WRITE_EVENT的作用
本Event是INSERT語句生成的Event,主要用于記錄INSERT語句的after_image實際數據,其中還包含 table_id、映像位圖、字段數量、行數據位圖等信息。實際上所有的 DML 語句雖然從客戶端看都是一條語句,但是Event記錄的時候都是以行為單位的,而且是更改一行記錄一行,3.2節將詳細說明這個流程。
2.源碼重要接口
本Event和后面的UPDATE_EVENT和DELETE_EVENT都來自同一個父類Rows_log_event。
主庫
· 初始化構造函數:Write_rows_log_event::Write_rows_log_event(THD* ,TABLE* ,const Table_id& table_id,bool is_transactional,const uchar* extra_row_info)。
· 數據寫入函數:Rows_log_event::do_add_row_data。
· 寫入binlog cache函數:Rows_log_event::write_data_header,Rows_log_event::write_data_body。
從庫
· 讀取構造函數:Write_rows_log_event(const char *buf,uint event_len,const Format_description_event *description_event)。
· 應用函數:Rows_log_event::do_apply_event。
3.主體格式
本Event的主體格式如圖2-7所示。

圖2-7
其中,固定部分如下。
table_id:6 字節,我們看到本 Event 中并沒有包含訪問表的具體信息,只包含了一個table_id。因為我們的MAP_EVENT中已經包含了相應的table_id到實際訪問表的映射,這里記錄table_id就可以了。
Reserved:2字節,保留以后使用。
可變部分如下。
var_header_len:當前2字節,通常為0x02 00。可以參考Rows_log_event::write_data_header函數。
columns_width:字段個數。
columns_after_image:after_image為位圖,最少1字節。這里主要表示Event中是否需要記錄全部的字段值,受到參數binlog_row_image影響,后面會單獨討論。這里需記住,如果參數binlog_row_image設置為FULL,那么columns_after_image會記錄為0xff,如下。

row Bit-field:位圖,最少1字節。這個數據是行數據自帶的,也就是構造Event的時候傳入的,每位代表一個字段。如果有實際數據則為0,否則為1。注意在MAP_EVENT中,有一個表示字段屬性是否可以為NULL的位圖m_null_bits,這里的位圖是某個字段數據是否實際為NULL,兩者并不一樣。
row real data:實際行數據。這個數據是行數據自帶的,按照字段的順序排列。
4.實例解析
我們進行如下操作。


使用解析語句如下。

結果如下。

解析如下。
7e 00 00 00 00 00:table_id,十六進制值7e,即十進制值126。
01 00:保留。
02 00:固定為0x02 00。
03:字段個數。
ff:columns_after_image,如果參數binlog_row_image設置為FULL,則固定為0xff。
f8:位圖,轉換為二進制值11111000,代表3列都有實際數據。
01 00 00 00:實際數據為1。
07 67 61 6f 70 65 6e 67:0x07表示可變長度類型varchar的長度為7字節,67 61 6f 70 65 6e 67為gaopeng字符串的ASCII編碼。
03 00 00 00:實際數據為3。
5.生成時機
本Event只會在行模式下生成,后面我們馬上要講的UPDATE_EVENT/DELETE_EVENT和它一樣,通常它們生成的時機都是在第一條數據在InnoDB層變更完成,并且在QUERY_EVENT和MAP_EVENT之后。
6.修改多行數據
如果需要變更的數據不止一行,那么怎么處理呢?DML 語句可以使用一條語句變更多條數據,在這種情況下,只需要將行數據增加到這個 Event 就可以了,參考Rows_log_event::do_add_row_data函數。
一個Event可以無限大嗎?顯然是不行的,在 THD::binlog_prepare_pending_rows_event函數中有如下判斷。

我們可以清晰地看到,如果本次加入的數據(needed)加上已有的數據的大小大于opt_binlog_rows_event_max_size的設置,那么就會建立一個新的Event來繼續存儲。opt_binlog_rows_event_max_size的實際大小是8192字節,如下。

因此,我們可以認為一個DML Event中可以包含多行數據,但是其大小應該在8192字節左右,大事務可能包含多個DML Event。
7.寫入binlog cache的時機
如上所述,如果DML語句涉及多行數據的變更,根據修改量的大小可能生成多個DML Event。那么它們在什么時候寫入binlog cache呢?實際上,MySQL每次新開啟一個DML Event之后都會將現有的Event寫入binlog cache,下面是THD::binlog_prepare_pending_rows_event函數的片段。

因此,并不需要等到所有的DML Event都生成后才一次性寫入binlog cache,那樣會帶來更多的內存消耗,是不可取的。
后面的UPDATE_EVENT和DELETE_EVENT的生成時機和寫入binglog cache的時機都和這里的WRITE_EVENT一致,就不再詳細描述了。
- C#高級編程(第10版) C# 6 & .NET Core 1.0 (.NET開發經典名著)
- Web應用系統開發實踐(C#)
- 國際大學生程序設計競賽中山大學內部選拔真題解(二)
- Mastering AWS Lambda
- 樂學Web編程:網站制作不神秘
- 移動界面(Web/App)Photoshop UI設計十全大補
- Node.js Design Patterns
- Python爬蟲、數據分析與可視化:工具詳解與案例實戰
- Drupal Search Engine Optimization
- Learning Cocos2d-JS Game Development
- 例解Python:Python編程快速入門踐行指南
- Java服務端研發知識圖譜
- Python網絡爬蟲從入門到實踐
- Slick2D Game Development
- 3ds Max瘋狂設計學院