【细如狗】记录一次使用MySQL的Binlog进行数据回滚的完整流程
文章目录
- 1 事情起因
- 2 解决思路
- 3 利用binlog进行数据回滚
-
- 3.1 确认是否启用Binlog日志
- 3.2 确认是否有binlog文件
- 3.3 找到误操作的时间范围
- 3.4 登录MySQL服务器查找binlog文件
-
- 3.4.1 查询binlog文件路径
- 3.4.2 找到binlog文件
- 3.4.3 确认误操作被存储在哪一份binlog文件中
- 3.5 查看二进制日志文件内容
-
- 3.5.1 利用被更新的表名筛选出大概的时间点
- 3.5.2 对每个时间点进行查询,找出误操作的具体时间和记录
- 3.5.3 找到误操作的记录
- 3.6 保存误操作的记录日志
- 3.7 分析记录,得出需要逆向解析SQL的思路
- 3.8 编写脚本解析记录,得到SQL
- 3.9 执行SQL语句,实现回滚
- 4 最后
1 事情起因
在最近的一次开发过程中,由于错将eq写成了set,导致全表数据被修改(还好是测试环境??)


2 解决思路
利用MySQL的binlog进行数据回滚
- 利用binlog文件查询到修改的那一条记录
- 对记录进行反向解析,获取被修改前数据的Update语句
- 执行解析后的Update语句,恢复数据
3 利用binlog进行数据回滚
3.1 确认是否启用Binlog日志
SHOW VARIABLES LIKE 'log_bin';

3.2 确认是否有binlog文件
SHOW BINARY LOGS;

3.3 找到误操作的时间范围
这一步仅仅是为了缩小排查区间
可以通过对应服务的日志查询出大概的误操作时间范围
3.4 登录MySQL服务器查找binlog文件
3.4.1 查询binlog文件路径
-
打开MySQL配置文件(通常是/etc/my.cnf或/etc/mysql/my.cnf)
- 找到与这个相似的配置(binlog存储路径):log-bin=/var/lib/mysql/mysql-bin

-
如果找不到上述配置,采用另外一种思路获取binlog文件路径,查询日志文件名或索引文件名,能带出binlog的存储路径
-
-- 用于查看 MySQL 服务器的二进制日志文件的基本文件名。SHOW VARIABLES LIKE 'log_bin_basename'; -

-
-- 用于查看 MySQL 服务器的二进制日志索引文件的名称。SHOW VARIABLES LIKE 'log_bin_index'; -

-
从获取到的结果来看,可以得出binlog是存在于/usr/local/src/mysql/data目录下的
-
3.4.2 找到binlog文件

3.4.3 确认误操作被存储在哪一份binlog文件中
我在执行误操作时大概是7月16日的14:30左右,所以应该查看的二进制日志文件是binlog.000034
3.5 查看二进制日志文件内容
3.5.1 利用被更新的表名筛选出大概的时间点
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 对每个时间点进行查询,找出误操作的具体时间和记录
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
这块需要能够对业务了解,大概知道哪些数据被更新为了什么,被更新了多少条
这样就能够定位到binlog中具体的那条记录了
--base64-output=DECODE-ROWS --verbose
字段命令的作用是base64解码:是因为binlog是Base64 编码的二进制数据,需要解码
3.5.3 找到误操作的记录
更新了多少行数据,这里就会有多少个UPDATE语句

这个操作记录中SET是被更新的数据,WHERE是原本的数据
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的思路
需要结合业务来看,哪些字段的数据被误更新了,以及3.5.3的图片为例
-
我将全表数据的 @4 和 @16都进行了错误更新
-
所以仅需要以主键ID(@1)作为条件,将旧数据(WHERE中)的@4 和 @16重新SET回去即可
-
结合日志记录,获取期望的更新语句样例为:
-
UPDATE 数据库.表名 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:\工作文件\技术文档\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);}}/*** 读取文本内容*/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();}/*** 解析文本内容*/private static List<String> parseDocument(String document) {List<String> updateStatements = new ArrayList<>();// 每个"### UPDATE "是一条更新语句String[] sections = document.split("### UPDATE ");for (int i = 1; i < sections.length; i++) {String section = sections[i];String[] lines = section.split("
");// 待拼接的WHERE条件String whereClause = "";// 待拼接的SETStringBuilder 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的内容,跳过即可if (line.startsWith("### SET")){break;}}// 拼接SQLString updateStatement = "UPDATE hm_product.item_code_distributor_rel " + "SET " + sb + " WHERE " + whereClause + ";";updateStatements.add(updateStatement);}return updateStatements;}
}
3.9 执行SQL语句,实现回滚
UPDATE hm_product.item_code_distributor_rel SET item_code = 'Ot2djSzc8e',order_channel_id = NULL WHERE id = 1;
..........省略N多条.......
4 最后
这次事情的起因也是因为一次编写代码的粗心造成的,虽然造成的影响不太好,但是解决问题的过程也挺有趣的。
如果还有别的好方案的话,欢迎在评论区分享。
欢迎大家收藏,但是最好别用到。
感谢大家看到这里,文章如有不足,欢迎大家指出;彦祖点个赞吧彦祖点个赞吧彦祖点个赞吧,欢迎关注程序员五条!
相关文章:
【细如狗】记录一次使用MySQL的Binlog进行数据回滚的完整流程
文章目录 1 事情起因2 解决思路3 利用binlog进行数据回滚 3.1 确认是否启用Binlog日志3.2 确认是否有binlog文件3.3 找到误操作的时间范围3.4 登录MySQL服务器查找binlog文件 3.4.1 查询binlog文件路径3.4.2 找到binlog文件3.4.3 确认误操作被存储在哪一份binlog文件中 3.5 查…...
什么是云原生数据库 PolarDB?
云原生数据库 PolarDB 是阿里云推出的一款高性能、兼容性强、弹性灵活的关系型数据库产品。它基于云原生架构设计,结合分布式存储和计算分离的技术优势,为用户提供强大的计算能力、卓越的可靠性以及高性价比的数据库解决方案。PolarDB 适合各种业务场景&…...
Kafka Stream实战教程
Kafka Stream实战教程 1. Kafka Streams 基础入门 1.1 什么是 Kafka Streams Kafka Streams 是 Kafka 生态中用于 处理实时流数据 的一款轻量级流处理库。它利用 Kafka 作为数据来源和数据输出,可以让开发者轻松地对实时数据进行处理,比如计数、聚合、…...
BEPUphysicsint定点数3D物理引擎使用
原文:BEPUphysicsint定点数3D物理引擎使用 - 哔哩哔哩 上一节給大家介绍了BEPUphysicsint的一些基本的情况,这节课我们来介绍它的基本使用,本节主要从以下5个方面来介绍: (1) 创建一个物理世界Space,并开启模拟迭代; (2) 添加一个物理物体…...
Splatter Image运行笔记
文章标题:Splatter Image: Ultra-Fast Single-View 3D Reconstruction 1. 环境配置 下载Splatter Image代码 git clone https://github.com/szymanowiczs/splatter-image.git 创建环境 conda create --name splatter-image python3.8 激活环境 conda activat…...
python爬虫--某房源网站验证码破解
文章目录 使用模块爬取目标验证码技术细节实现成果代码实现使用模块 requests请求模块 lxml数据解析模块 ddddocr光学识别 爬取目标 网站验证码破解思路是统一的,本文以城市列表为例 目标获取城市名以及城市连接,之后获取城市房源信息技术直接替换地址即可 验证码 技术…...
Micropython编译ESP32C3开发板版本过程详细步骤步骤
一、环境说明 开发板:合宙ESP32-C3 工作机器CPU:AMD64 操作系统:Windows10 2004(19041.508) 使用WSL2安装Linux系统 Linux:Ubuntu 24.04.1 LTS python:python 3.12.3(Windows和…...
【开源免费】基于SpringBoot+Vue.JS大创管理系统(JAVA毕业设计)
博主说明:本文项目编号 T 081 ,文末自助获取源码 \color{red}{T081,文末自助获取源码} T081,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…...
mysql 和 tidb的区别
MySQL 和 TiDB 是两种常见的关系型数据库管理系统,但它们的设计理念和适用场景有显著区别。以下从架构、性能、扩展性、适用场景等方面进行对比: 架构设计 MySQL 单机架构为主,可通过主从复制实现读写分离或高可用。分布式支持依赖外部组件&…...
传输层5——TCP可靠传输的实现(重点!!)
TCP协议如何实现可靠传输?确保接收方收到数据? 需要依靠几个结构: 以字节为单位的滑动窗口 这其中包括发送方的发送窗口和接收方的接收窗口 下面的描述,我们指定A为发送端口,B为接收端口 TCP的可靠传输就是靠着滑动窗口…...
基于Python实现web网页内容爬取
文章目录 1. 网页分析2. 获取网页信息2.1 使用默认的urllib.request库2.2 使用requests库1.3 urllib.request 和 requests库区别 2. 更改用户代理3. BeautifulSoup库筛选数据3.1 soup.find()和soup.find_all() 函数 4. 抓取分页链接参考资料 在日常学习和工作中,我们…...
Centos7和9安装mysql5.7和mysql8.0详细教程(超详细)
目录 一、简介 1.1 什么是数据库 1.2 什么是数据库管理系统(DBMS) 1.3 数据库的作用 二、安装MySQL 1.1 国内yum源安装MySQL5.7(centos7) (1)安装4个软件包 (2)找到4个软件包…...
星闪WS63E开发板的OpenHarmony环境构建
目录 引言 关于SDK 安装步骤 1. 更新并安装基本依赖 2. 设置 Python 3.8 为默认版本 3. 安装 Python 依赖 4. 安装有冲突的包 5. 设置工作目录 6. 设置环境变量 7. 下载预构建文件以及安装编译工具 8. 编译工程 nearlink_dk_3863 设置编译产品 编译 制品存放路径…...
MongoDB数据建模小案例
MongoDB数据建模小案例 朋友圈评论内容管理 需求 社交类的APP需求,一般都会引入“朋友圈”功能,这个产品特性有一个非常重要的功能就是评论体系。 先整理下需求: 这个APP希望点赞和评论信息都要包含头像信息: 点赞列表,点赞用户的昵称,头像;评论列表,评论用户的昵称…...
MySQL(库的操作)
目录 1. 创建数据库 2. 删除数据库 3. 查看数据库 4. 修改数据库 5. 备份和恢复 6. 查看连接情况 1. 创建数据库 CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] 1. 大写的是关键字 2. [ ]可带可不带 3. db_name 数据…...
【55 Pandas+Pyecharts | 实习僧网Python岗位招聘数据分析可视化】
文章目录 🏳️🌈 1. 导入模块🏳️🌈 2. Pandas数据处理2.1 读取数据2.2 查看数据信息2.3 去除重复数据2.4 调整部分城市名称 🏳️🌈 3. Pyecharts数据可视化3.1 招聘数量前20岗位3.2 各城市招聘数量3…...
java中23种设计模式的优缺点
文兴一言 设计模式分为创建型模式、结构型模式和行为型模式。以下是每种设计模式及其优缺点的详细介绍: 一、创建型模式 简单工厂模式 优点:通过一个共同的工厂类来创建对象,将对象的创建逻辑封装在一个地方,客户端只需要与工厂…...
【JavaEE】多线程(7)
一、JUC的常见类 JUC→java.util.concurrent,放了和多线程相关的组件 1.1 Callable 接口 看以下从计算从1加到1000的代码: public class Demo {public static int sum;public static void main(String[] args) throws InterruptedException {Thread …...
如何高效的向AI大模型提问? - 提示工程Prompt Engineering
大模型的输入,决定了大模型的输出,所以一个符合要求的提问Prompt起到关键作用。 以下是关于提示工程Prompt Engineering主要方法的详细表格,包括每种方法的优点、缺点、应用场景以及具体示例: 主要方法优点缺点应用场景示例明确性…...
4K高清壁纸网站推荐
1. Awesome Wallpapers 官网: https://4kwallpapers.com/ 主题: 创意、摄影、人物、动漫、绘画、视觉 分辨率: 4K Awesome Wallpapers 提供了丰富的高质量图片,分为通用、动漫、人物三大类,可以按屏幕比例和分辨率检索,满足你对壁纸的各种…...
为什么92%的DeepSeek私有化部署在K8s上遭遇OOMKilled?——GPU内存隔离、vLLM适配与cgroups v2调优三重解法
更多请点击: https://intelliparadigm.com 第一章:DeepSeek私有化部署的Kubernetes现状与OOMKilled困局 当前,DeepSeek系列大模型在企业私有化场景中广泛采用Kubernetes进行容器化编排部署。然而,实际落地过程中,内存…...
独立开发者利用Taotoken统一API开发跨模型内容生成应用案例
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 独立开发者利用Taotoken统一API开发跨模型内容生成应用案例 应用场景类,一位独立开发者希望构建一个能同时调用多种大模…...
3步实现电脑风扇智能控制:FanControl.HWInfo插件终极指南
3步实现电脑风扇智能控制:FanControl.HWInfo插件终极指南 【免费下载链接】FanControl.HWInfo FanControl plugin to import HWInfo sensors. 项目地址: https://gitcode.com/gh_mirrors/fa/FanControl.HWInfo 还在为电脑风扇的噪音烦恼吗?或者担…...
ComfyUI-Impact-Pack终极指南:快速掌握AI图像增强的完整教程
ComfyUI-Impact-Pack终极指南:快速掌握AI图像增强的完整教程 【免费下载链接】ComfyUI-Impact-Pack Custom nodes pack for ComfyUI This custom node helps to conveniently enhance images through Detector, Detailer, Upscaler, Pipe, and more. 项目地址: ht…...
爆单实操课:从3C到美妆,跨境商家如何用AI神器搞定TikTok本土化
每天都有无数跨境卖家在各大社群里发问:怎么用ai生成带货视频,有哪些工具比较好用? 在 TikTok 这个极度依赖内容爆发的平台上,不同类目的产品对视频素材的需求千差万别。靠人工剪辑不仅效率低,且极难跨越本土化语言的障…...
通过curl命令直接测试Taotoken聊天补全接口的配置与排错方法
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 通过curl命令直接测试Taotoken聊天补全接口的配置与排错方法 对于开发者而言,在集成大模型API时,直接使用c…...
条件生成对抗网络实现可控人脸老化建模
1. 项目概述:用条件生成对抗网络实现可控的人脸老化模拟“Face Aging Using Conditional GANs”——这个标题一出现,我就知道它不是那种调个预训练模型跑个demo的轻量级练习。它直指一个在计算机视觉与人机交互交叉领域里既经典又棘手的问题:…...
渗透PHP伪协议
一、debug调试 1、定义 Debug,又叫断点调试,就是对写好的程序进行逐步运行、分解、调试的过程,通过这个过程,我们可以跟踪程序的详细运行过程, 是程序员的开发神器,也是开发必会的一个重要技能。 2、意义…...
别只把Docker当虚拟机!《Docker实践》没细说的5个生产环境‘骚操作’
别只把Docker当虚拟机!5个生产环境高阶实践指南 当团队从开发测试转向生产环境时,Docker的使用方式往往需要质的飞跃。许多工程师在初期将容器简单视为轻量级虚拟机,却忽略了容器化架构真正的威力。本文将揭示那些官方文档鲜少提及࿰…...
收藏必备!小白程序员轻松入门大模型:ReAct与Reflexion核心技术与实战应用
大语言模型(LLM)在复杂任务中存在事实幻觉、缺乏实时信息等局限。本文介绍ReAct和Reflexion两大提示技术框架,ReAct通过推理与行动协同,有效解决幻觉问题;Reflexion在ReAct基础上增加自我反思机制,形成闭环…...
