最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用MySQL的Binlog進(jìn)行數(shù)據(jù)回滾的完整流程

 更新時(shí)間:2025年12月03日 09:44:35   作者:e***2829  
本文描述了使用MySQL的binlog進(jìn)行數(shù)據(jù)回滾的過(guò)程,從確認(rèn)是否啟用Binlog日志到找到誤操作的記錄,再到編寫腳本解析記錄,最后執(zhí)行SQL語(yǔ)句實(shí)現(xiàn)回滾,需要的朋友可以參考下

1 事情起因

在最近的一次開發(fā)過(guò)程中,由于錯(cuò)將eq寫成了set,導(dǎo)致全表數(shù)據(jù)被修改(還好是測(cè)試環(huán)境)

2 解決思路

利用MySQL的binlog進(jìn)行數(shù)據(jù)回滾

  • 利用binlog文件查詢到修改的那一條記錄
  • 對(duì)記錄進(jìn)行反向解析,獲取被修改前數(shù)據(jù)的Update語(yǔ)句
  • 執(zhí)行解析后的Update語(yǔ)句,恢復(fù)數(shù)據(jù)

3 利用binlog進(jìn)行數(shù)據(jù)回滾

3.1 確認(rèn)是否啟用Binlog日志

SHOW VARIABLES LIKE 'log_bin';

3.2 確認(rèn)是否有binlog文件

SHOW BINARY LOGS;

3.3 找到誤操作的時(shí)間范圍

這一步僅僅是為了縮小排查區(qū)間

可以通過(guò)對(duì)應(yīng)服務(wù)的日志查詢出大概的誤操作時(shí)間范圍

3.4 登錄MySQL服務(wù)器查找binlog文件

3.4.1 查詢binlog文件路徑

打開MySQL配置文件(通常是/etc/my.cnf或/etc/mysql/my.cnf)

找到與這個(gè)相似的配置(binlog存儲(chǔ)路徑):log-bin=/var/lib/mysql/mysql-bin

如果找不到上述配置,采用另外一種思路獲取binlog文件路徑,查詢?nèi)罩疚募蛩饕募?,能帶出binlog的存儲(chǔ)路徑

    -- 用于查看 MySQL 服務(wù)器的二進(jìn)制日志文件的基本文件名。
    SHOW VARIABLES LIKE 'log_bin_basename';

    -- 用于查看 MySQL 服務(wù)器的二進(jìn)制日志索引文件的名稱。
    SHOW VARIABLES LIKE 'log_bin_index'; 

從獲取到的結(jié)果來(lái)看,可以得出binlog是存在于/usr/local/src/mysql/data目錄下的

3.4.2 找到binlog文件

3.4.3 確認(rèn)誤操作被存儲(chǔ)在哪一份binlog文件中

我在執(zhí)行誤操作時(shí)大概是7月16日的14:30左右,所以應(yīng)該查看的二進(jìn)制日志文件是binlog.000034

3.5 查看二進(jìn)制日志文件內(nèi)容

3.5.1 利用被更新的表名篩選出大概的時(shí)間點(diǎn)

mysqlbinlog --no-defaults --start-datetime="2024-07-16 14:00:00" --stop-datetime="2024-07-16 15:00:00" binlog.000034 | grep -i 'item_code_distributor_rel'

3.5.2 對(duì)每個(gè)時(shí)間點(diǎn)進(jìn)行查詢,找出誤操作的具體時(shí)間和記錄

mysqlbinlog --no-defaults --start-datetime="2024-07-16 14:50:27" --stop-datetime="2024-07-16 14:50:28" --base64-output=DECODE-ROWS --verbose binlog.000034 | less

這塊需要能夠?qū)I(yè)務(wù)了解,大概知道哪些數(shù)據(jù)被更新為了什么,被更新了多少條

這樣就能夠定位到binlog中具體的那條記錄了

--base64-output=DECODE-ROWS --verbose 
字段命令的作用是base64解碼:是因?yàn)閎inlog是Base64 編碼的二進(jìn)制數(shù)據(jù),需要解碼

3.5.3 找到誤操作的記錄

更新了多少行數(shù)據(jù),這里就會(huì)有多少個(gè)UPDATE語(yǔ)句

這個(gè)操作記錄中SET是被更新的數(shù)據(jù),WHERE是原本的數(shù)據(jù)

3.6 保存誤操作的記錄日志

mysqlbinlog --no-defaults --start-datetime="2024-07-16 14:50:27" --stop-datetime="2024-07-16 14:50:28" --base64-output=DECODE-ROWS --verbose binlog.000034 > cjh_get_parsed_binlog_2024-07-16-17-05.sql

3.7 分析記錄,得出需要逆向解析SQL的思路

需要結(jié)合業(yè)務(wù)來(lái)看,哪些字段的數(shù)據(jù)被誤更新了,以及3.5.3的圖片為例

我將全表數(shù)據(jù)的 @4@16都進(jìn)行了錯(cuò)誤更新

所以僅需要以主鍵ID(@1)作為條件,將舊數(shù)據(jù)(WHERE中)的@4@16重新SET回去即可

結(jié)合日志記錄,獲取期望的更新語(yǔ)句樣例為:

    UPDATE 數(shù)據(jù)庫(kù).表名 SET @4的字段名 = @4,@16的字段名 = @16 WHERE @1的字段名 = @1;

3.8 編寫腳本解析記錄,得到SQL

package pers.chenjiahao.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ChenJiahao(五條)
 * @date 2024/7/16 17:36
 */
public class MySQLBinaryLogParser {
    public static void main(String[] args) {
        String filePath = "D:工作文件技術(shù)文檔cjh_get_parsed_binlog_2024-07-16-17-05.sql";
        String document = readFileContent(filePath);
        List<String> updateStatements = parseDocument(document);
        for (String statement : updateStatements) {
            System.out.println(statement);
        }
    }

    /**
     * 讀取文本內(nèi)容
     */
    private static String readFileContent(String filePath) {
        StringBuilder content = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(new File(filePath)))) {
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line).append("
");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return content.toString();
    }

    /**
     * 解析文本內(nèi)容
     */
    private static List<String> parseDocument(String document) {
        List<String> updateStatements = new ArrayList<>();

		// 每個(gè)"### UPDATE "是一條更新語(yǔ)句
        String[] sections = document.split("### UPDATE ");
        for (int i = 1; i < sections.length; i++) {
            String section = sections[i];
            String[] lines = section.split("
");

			// 待拼接的WHERE條件
            String whereClause = "";
            // 待拼接的SET
            StringBuilder sb = new StringBuilder();

            for (String line : lines) {
                if (line.startsWith("###   @1=")) {
                    whereClause = "id = " + line.split("=")[1];
                }else if (line.startsWith("###   @4=")) {
                    sb.append("item_code = " + line.split("=")[1]);
                }else if (line.startsWith("###   @16=")) {
                    sb.append(",order_channel_id = " + line.split("=")[1]);
                }

				// 不需要讀取日志文件中SET的內(nèi)容,跳過(guò)即可
                if (line.startsWith("### SET")){
                    break;
                }
            }

			// 拼接SQL
            String updateStatement = "UPDATE hm_product.item_code_distributor_rel " + "SET " + sb + " WHERE " + whereClause + ";";

            updateStatements.add(updateStatement);
        }

        return updateStatements;
    }
}

3.9 執(zhí)行SQL語(yǔ)句,實(shí)現(xiàn)回滾

UPDATE hm_product.item_code_distributor_rel SET item_code = 'Ot2djSzc8e',order_channel_id = NULL WHERE id = 1;
..........省略N多條.......

4 最后

這次事情的起因也是因?yàn)橐淮尉帉懘a的粗心造成的,雖然造成的影響不太好,但是解決問(wèn)題的過(guò)程也挺有趣的。

以上就是使用MySQL的Binlog進(jìn)行數(shù)據(jù)回滾的完整流程的詳細(xì)內(nèi)容,更多關(guān)于MySQL Binlog數(shù)據(jù)回滾的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

汉阴县| 渭南市| 缙云县| 樟树市| 乌鲁木齐市| 东乡| 密山市| 密云县| 南澳县| 辽中县| 广宗县| 永宁县| 福泉市| 潮安县| 余干县| 平昌县| 高碑店市| 南充市| 读书| 德惠市| 奉化市| 郯城县| 湄潭县| 平安县| 周宁县| 沂水县| 济宁市| 孟连| 九台市| 东平县| 福海县| 河池市| 周宁县| 巴塘县| 缙云县| 正安县| 伊春市| 上饶市| 岳池县| 玛沁县| 湟中县|