MySQL 如何从 Binlog 找出变更记录并回滚

文章目录

    • 前言
    • 1. 案例模拟
      • 1.1 确认信息
      • 1.2 下载 Binlog
      • 1.3 准备环境
      • 1.4 注册 Binlog
      • 1.5 准备结构信息
      • 1.6 Python 订阅
      • 1.7 输出结果展示
    • 2. 原理解析
      • 2.1 程序设计
      • 2.2 模块版本
    • 总结

前言

最近有研发同学问我:有一个问题,想查一个 ID 为 xxxx 的 sku 什么时候被更新了吗?更新前的数据是什么?一般这么讲,可能是由于手动执行或者是代码 Bug 导致出现数据丢失或者数据误更新,需要确认订正,一般需要通过分析 Binlog 来解决,本篇文章将通过该案例介绍此类问题的处理思路。

1. 案例模拟

1.1 确认信息

当有需求需要从 Binlog 中查询变更记录或者需要闪回数据的时候,需要和研发确认 时间范围、涉及到的 环境信息、库名、表名 最好是可以提供 SQL 语句。在上述的案例中,研发提供的是 sku 的 ID 时间范围是 2024-02-22 18:01:42 ~ 18:03:42。

1.2 下载 Binlog

阿里云、腾讯云、华为云 的数据库服务 Binlog 都是支持直接下载的,按照研发提供的时间区间下载对应的 Binlog 日志。
在这里插入图片描述
如果是本地自建的 MySQL 数据库,是没用日志开始时间和日志结束时间的,需要先确认下时间。可参考下方文档。

推荐阅读:MySQL 查询 Binlog 生成时间

1.3 准备环境

Binlog 下载完成后,那我们想要的数据记录也在里面,接下来将介绍如何获得我们想要的记录,首先需要准备一台测试数据库(作为数据库管理人员,随身带一套 MySQL 测试环境不过分吧?)测试数据库的大版本需要和生产环境的版本大版本一致。

以下是我环境信息:

  • 生产环境 MySQL 5.7.18
  • 测试环境 MySQL 5.7.33 (单实例)

1.4 注册 Binlog

该步骤,需要把从云上下载的 Binlog 注册到我们的测试环境中,首先需要先清空测试环境中的 Binlog 日志。

reset master;

查询 Binlog 索引文件的位置:

show variables like 'log_bin_index';

将我们从生产环境下载的 Binlog 拷贝到测试环境 Binlog 目录,然后再按照 mysql-bin.index 文件中的格式,将 Binlog 写进去。

/data/mysql_57/logs/mysql-bin.000001
/data/mysql_57/logs/mysql-bin.000002
/data/mysql_57/logs/mysql-bin.000003
/data/mysql_57/logs/mysql-bin.000004
/data/mysql_57/logs/mysql-bin.000005

上面,是注册完成的 Binlog 索引文件信息,生产环境下载了 5 个 Binlog 他们分别是 008213、008214、008215、008216、008217,拷贝到测试环境后,我们将原来 Binlog 名字修改为从 000001 开始,并且是顺序的。注意给拷贝来的 Binlog 设置用户属组。

chown -R mysql:mysql mysql-bin.*

设置完成后,重启测试环境的数据库,注册阶段完成。

1.5 准备结构信息

该步骤,需要把生产环境的表结构 copy 一份到测试环境。不用全部 copy 只 copy 需要查询记录的表。例如上面的 case 我们要查 product 库下的 sku 表。就在测试环境创建一个 product 库,然后将生产环境 sku 的表结构 copy 到测试环境。

create database product;
use product;

-- 不在此展示完成结构了,与生产环境保持一致就行
create table sku(.........)

create table sku_price(.........)

需要查询到记录涉及到多少张表,那么就 copy 多少张表就行。这次案例涉及到 2 张表。

1.6 Python 订阅

该步骤,要从 5 个 Binlog 文件中搜索到我们想要的记录,一个 Binlog 中可能有几十万个事务,这里我们通过编写 Python 脚本简化操作。我们要搜索的是 product 库下 sku、sku_price 表 sku_id = 810827 的变更记录,只需要按照下方代码注释修改即可。

在准备结构信息的步骤中,我们只在注册服务器中创建了需要的表,就起到了过滤表的作用,所以代码中不需要指定表名。

# -*- coding: utf-8 -*-
import sys
from datetime import datetime
from decimal import Decimal
from pymysqlreplication import BinLogStreamReader
from pymysqlreplication.row_event import (
    DeleteRowsEvent,
    UpdateRowsEvent,
    WriteRowsEvent
)
from pymysqlreplication.event import XidEvent, QueryEvent

# 填写注册 MySQL 连接信息
mysql_settings = {
    'host': '172.16.104.56',
    'port': 3306,
    'user': 'bing',
    'password': 'abc123'
}

stream = BinLogStreamReader(
    connection_settings=mysql_settings,
    server_id=8023,
    log_file='mysql-bin.000001',  # 从哪个 Binlog 开始扫描
    log_pos=4,
    only_schemas='product',  # 数据库名称
    only_events=[
        DeleteRowsEvent,
        UpdateRowsEvent,
        WriteRowsEvent,
    ]
)


def simple_data_type(data_info: dict):
    """
    直接打印结果会包含一些对象信息,在这里简化处理
    """
    tem_data = {}
    for key, value in data_info.items():
        if isinstance(value, Decimal):
            tem_data[key] = float(value)
        elif isinstance(value, datetime):
            tem_data[key] = value.strftime('%Y-%m-%d %H:%M:%S')
        else:
            tem_data[key] = value
    return tem_data


search_file_name = None

for binlog_event in stream:
    if search_file_name == stream.log_file:
        pass
    elif search_file_name != stream.log_file:
        search_file_name = stream.log_file
        print('正在扫描:', search_file_name)

    for row in binlog_event.rows:

        try:
            event_time = datetime.fromtimestamp(binlog_event.timestamp)
        except OSError:
            event_time = datetime(1980, 1, 1, 0, 0)

        if isinstance(binlog_event, DeleteRowsEvent):
            df = row["values"]
            # 这里条件,需要自己改
            if int(df['sku_id']) == 810887:
                print('-' * 160)
                print('操作类型: DELETE')
                print('时间: ', event_time)
                print('日志文件: ', stream.log_file)
                print('数据库名:', binlog_event.schema)
                print('表名:', binlog_event.table)
                print('Position: ', binlog_event.packet.log_pos)
                print(simple_data_type(df))
                print('-' * 160)

        elif isinstance(binlog_event, UpdateRowsEvent):
            df = row["before_values"]
            # 这里条件,需要自己改
            if int(df['sku_id']) == 810827:
                print('-' * 160)
                print('操作类型: UPDATE')
                print('时间: ', event_time)
                print('日志文件: ', stream.log_file)
                print('数据库名:', binlog_event.schema)
                print('表名:', binlog_event.table)
                print('Position: ', binlog_event.packet.log_pos)
                print('before_values: ', simple_data_type(row["before_values"]))
                print('after_values: ', simple_data_type(row["after_values"]))

        elif isinstance(binlog_event, WriteRowsEvent):
            df = row["values"]
            # 这里条件,需要自己改
            if int(df['sku_id']) == 810827:
                print('-' * 160)
                print('操作类型: INSERT')
                print('时间: ', event_time)
                print('日志文件: ', stream.log_file)
                print('数据库名:', binlog_event.schema)
                print('表名:', binlog_event.table)
                print('Position: ', binlog_event.packet.log_pos)
                print(simple_data_type(df))

1.7 输出结果展示

结果已脱敏,可以看出 boutique_price 从原来的 1058.46 被修改为 1614.0,需要注意的是 Binlog 中的 Event 只能精确到秒。

操作类型: UPDATE
时间:  2024-02-22 18:02:42
日志文件:  mysql-bin.000003
数据库名: product
表名: sku
Position:  65716973
before_values:  {'sku_id': 810887, 'product_id': 26492, 'sku_code': '000', 'name': '', 'coverpic': '', 'introduction': '', 'in_price': 132.31, 'price': 361.1, 'created_at': '2022-11-18 13:37:48', 'updated_at': '2024-02-21 04:10:41', 'enabled': '1', 'retail_price': None, 'im_price': 150.0, 'last_check': '2022-11-18 13:37:48', 'size': 'UNI', 'boutique_price': 1058.46}
after_values:  {'sku_id': 810887, 'product_id': 26492, 'sku_code': '000', 'name': '', 'coverpic': '', 'introduction': '', 'in_price': 132.31, 'price': 361.1, 'created_at': '2022-11-18 13:37:48', 'updated_at': '2024-02-22 18:02:42', 'enabled': '1', 'retail_price': None, 'im_price': 150.0, 'last_check': '2022-11-18 13:37:48', 'size': 'UNI', 'boutique_price': 1614.0}

将结果交给研发,任务就算完成了。

2. 原理解析

2.1 程序设计

这里用到了一个模块 pymysqlreplication 它可以伪装成一个 IO 复制线程,从 MySQL 服务器中拉取 Binlog Event 并支持解析。

为什么直接解析 Binlog?因为 Binlog 中没用表字段名信息,直接解析比较难做一些过滤操作。先将表结构和 Binlog 注册到一台测试 MySQL 服务器,然后通过伪装 IO 复制线程拉取 Event 过滤找到我们想要的记录。

2.2 模块版本

模块代码库:python-mysql-replication

# 本次实验使用的版本
mysql-replication==0.13

安装方法:

pip3 install mysql-replication

总结

本篇文章介绍了如何从 Binlog 中定位记录,需要有一点 Python 基础,但注册 Binlog 思路可应用多个场景,例如使用它恢复增量日志等。得到记录结果后,如果要回滚,那么可以依靠上面的字典中的信息,翻译成 SQL 语句即可,目前程序还没有实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/416852.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

硬件工程师入门基础知识(三)钽电容应用(三)

钽电容安装测试说明 1.使用测量2.清洗电路板3.焊接4.推荐的高能混合电容器安装方法5.使用环境与贮存6.钽电容参数测试条件 将电容器安装在印刷电路板上时,如受到过大的机械冲击或热冲击等负荷,将引起电气特性劣化、开路、短路等,故请在确认实…

基于x86架构的OpenHarmony应用生态挑战赛等你来战!

为了更快速推进OpenHarmony在PC领域的进一步落地,加快x86架构下基于OpenHarmony的应用生态的繁荣,为北向应用开发者提供一个更加便捷的开发环境,推动OpenHarmony北向应用开发者的增加,助力OpenHarmony在PC领域实现新的突破&#x…

【机器学习】特征选择之包裹式特征选择法

🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:机器学习 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进…

TESTLINK 测试用例数据结构解析

一、node_types 测试组件信息表 我们查询表 select * from testlink.node_types; 得到如下结果 二、nodes_hierarchy 测试用例目录层次表 我们以下图的项目为例,来讲解 1、测试项目 首先,我们有个Train的项目,存在表testprojects中,可以用如下sql查找到 select * fr…

【Linux C | 网络编程】gethostbyname 函数详解及C语言例子

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…

软考-系统集成项目管理中级-信息系统建设与设计

本章重点考点 1.信息系统的生命周期 信息系统建设的内容主要包括设备采购、系统集成、软件开发和运维服务等。信息系统的生命周期可以分为四个阶段:立项、开发、运维和消亡。 2.信息系统开发方法 信息系统常用的开发方法有结构化方法、原型法、面向对象方法等 1)结构化方法 …

VS连接MySQL以及找不到libmysql.dll的解决方法

VS连接数据库需要在项目中进行配置,具体可见 https://blog.csdn.net/weixin_40582034/article/details/115562097?ops_request_misc%257B%2522request%255Fid%2522%253A%2522170891897216800213058288%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522…

前端开发——ElementUI组件的使用

文章目录 1. Tabs标签页2. 单选框 el-radio3. 复选框 el-checkbox4. 下拉框 el-select5. 表格 el-table6. 对话框 el-dialog7. 文字提示 el-tooltip8. 抽屉 el-drawer 1. Tabs标签页 <template><el-tabs v-model"activeName" tab-click"handleClick&q…

linux操作docker

docker地址 官方地址 centos7安装docker 卸载旧版本docker sudo //在前面表示以管理员权限操作yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine安装docker //安装所需资…

综合实战(volume and Compose)

"让我&#xff0c;重获新生~" MySQL 灾难恢复 熟练掌握挂载卷的使用&#xff0c;将Mysql的业务数据存储在 外部。 实战思想: 使用 MySQL 5.7 的镜像创建容器并创建一个普通数据卷 "mysql-data"用来保存容器中产生的数据。我们需要容器连接到Mysql服务&a…

流水账-20240229

目录 git本地回滚到到120bc409ee3b8f63a23d0060e55118bcce557acf提交记录本地提交到已有代码分支 IDEA批量导入快捷键无效更换背景主题快捷键快捷键可以设置eclipse模式&#xff0c;但是有些不生效&#xff0c;可能是冲突了Ctrl单击&#xff0c;Eclipse里面是可以跳转到代码内部…

数仓项目6.0(二)数仓

中间的几步意义就在于&#xff0c;缓存中间处理数据样式&#xff0c;避免重复计算浪费算力 分层 ODS&#xff08;Operate Data Store&#xff09; Spark计算过程中&#xff0c;存在shuffle的操作&#xff0c;而shuffle会将计算过程一分为二&#xff0c;前一阶段不执行完&…

单点登录的三种方式

前言 在B/S系统中&#xff0c;登录功能通常都是基于Cookie 来实现的。当用户登录成功后&#xff0c;一般会将登录状态记录到Session中&#xff0c;或者是给用户签发一个 Token&#xff0c;无论哪一种方式&#xff0c;都需要在客户端保存一些信息(Session ID或Token)&#xff0…

Leetcode股票问题总结篇!

Leetcode股票问题总结篇! https://programmercarl.com/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92-%E8%82%A1%E7%A5%A8%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93%E7%AF%87.html#%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA 卖股票的最佳时机 买卖股票…

网络工程师笔记5

TCP/IP 常见协议 应用层 Telnet 数据网络中提供远程登录服务的标准协议23FTP 传输文件协议21&#xff0c;20HTTP 超文本传输协议80TFTPSNMPSMTPDNSDHCP 传输层 TCPUDP 网络层 ICMPIGMPIP 数据链路层 PPPOE Internet PPP 传输层 传输层协议接收…

AI智能分析网关V4智慧商场方案,打造智慧化商业管理生态

AI智能视频检测技术在商场楼宇管理中的应用越来越广泛。通过实时监控、自动识别异常事件和智能预警&#xff0c;这项技术为商场管理提供了更高效、更安全的保障。今天我们以TSINGSEE青犀视频AI智能分析网关为例&#xff0c;给大家介绍一下AI视频智能分析技术如何应用在商场楼宇…

web组态(BY组态)接入流程

技术文档 官网网站&#xff1a;www.hcy-soft.com 体验地址&#xff1a; www.byzt.net:60/sm 一、数据流向图及嵌入原理 数据流向 嵌入原理 二、编辑器调用业务流程图 三、集成前需要了解的 1、后台Websocket端往前台监控画面端传输数据规则 后台websocket向客户端监控画面…

最新 PhpStorm 2023.3.4 下载与安装 + 永久免费

文章目录 Stage 1 : 官网下载Stage 2 : 下载工具Stage 3-1 : windows为例Stage 3-2 : mac为例常见问题部分小伙伴 Mac 系统执行脚本遇到如下错误&#xff1a;解决方法&#xff1a; Stage 1 : 官网下载 先去官网下载 我这里下载的是最新版本的2023.3.4&#xff0c;测试过2023最…

就业班 2401--2.28 Linux Day7--存储管理1

一 .存储管理 主要知识点: 基本分区、逻辑卷LVM、EXT3/4/XFS文件系统、RAID 初识硬盘 机械 HDD 固态 SSD SSD的优势 SSD采用电子存储介质进行数据存储和读取的一种技术&#xff0c;拥有极高的存储性能&#xff0c;被认为是存储技术发展的未来新星。 与传统硬盘相比&#…

使用Fragments(片段)提升你的Vue.js开发体验

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…
最新文章