内部群炸锅了,同事又删库了

news2024/10/7 2:38:23

事件起因

我们的系统中有数据导入的功能,可以把特定的格式的excel数据导入到系统中来

由于客户电脑的文件比较多,很多文件的名字也比较相近,客户在导入excel时选错了文件

这个错误的excel文件的格式恰好能被系统解析,客户也没及时发现导错了文件,所以就将6万多条没用的数据导入到了系统中

编辑

添加图片注释,不超过 140 字(可选)

这6万多条数据对系统来说就是无用的数据,不会影响系统的运行,最多也就是占用一点数据库空间而已

客户只需要把正确的excel重新导入,就可以继续完成他的业务了

但是,客户是一个重度强迫症患者,他觉得在管理平台看到这6万多条没用的数据令他抓狂

客户想要把这些数据删除,我们系统又没有提供批量删除功能,只能单个删除,这无疑是一个巨大的工作量

客户就通过客服部门找到了研发团队,想让我们研发人员从数据库中直接删除

删库经过

虽然在生产环境直接操作数据库明显是违规操作,但客户的要求又不得不满足,谁让人家是爸爸呢

编辑

添加图片注释,不超过 140 字(可选)

金主爸爸

由于生产环境的数据和表结构属于商业机密,我们讨论的重点也不在于数据和表结构,而是数据恢复的思路。所以我在测试环境新建了用户表,导入了一些测试数据,当作是生产环境进行操作

研发人员登录生产数据库,执行如下sql,找到了这6万多条错误数据。

 
 

select * from t_user where age>18 and deptid=100;

在确认这6万多条数据确实是错误导入的数据后就准备开始删除。由于表里面没有逻辑删除字段,所以只能进行物理删除

需要删除的数据已经确定,通常情况下把sql中的select *替换为delete去执行,出错的机率会小一点

但是,研发人员并没有去改原来的sql,而是重新写了一个删除语句并且执行

 
 

delete from t_user where age>18;

问题就这样出现了,在新写的删除语句中缺少了deptid=100的条件

不要问我为什么删除之前没有备份,这都是血泪的教训

重新查表后发现误删了10多万条数据

生产环境中,很多业务都依赖这个表,算是系统的核心表。虽然是只删除了10万条数据,但系统的很多功能无法正常使用,其实和删库没啥区别了

研发人员发现删库后,第一时间报告给了领导(居然没有第一时间跑路)

领导当机立断,要求系统停止运行,给所有客户发送停服通知,打开所有客服通道,处理客户投诉和答疑

同时,也安排研发人员进行数据找回,要求尽快搞定

数据找回

我们找到删库的研发人员询问他有没有备份,他的回答是没有

我们又去咨询运维的同事,看看生产环境有没有开启数据库定期自动备份,运维的回答也是没有

事情比较难办了,只能把希望寄托于mysql的binlog了。

binlog二进制日志文件,数据库的insert、delete、update、create、alter、drop等写入操作都会被binlog记录(下文对binlog有详细介绍)

binlog记录日志是需要开启配置的,希望生产环境的mysql数据库开启了binlog日志,否则只能找专业的磁盘数据恢复的第三方公司了

登录生产环境数据库,查看binlog是否开启

 
 

SHOW VARIABLES LIKE 'LOG_BIN%';

编辑切换为居中

添加图片注释,不超过 140 字(可选)

从图中可以看到log_bin是处于ON的状态,说明binlog是开启的

悬着的心终于放下了一大半,接下来就是想办法从binlog中把数据恢复就行了

从上图中也可以看到log_bin_basename是/var/lib/mysql/bin-log,说明binlog是存放在mysql所在的服务器的/var/lib/mysql目录下,文件是以bin-log开头,比如:bin-log.000001

登录mysql所在的服务器,进入到binlog所在的目录

 
 

cd /var/lib/mysql

查看binlog日志文件

编辑切换为居中

添加图片注释,不超过 140 字(可选)

binlog日志文件是滚动生成的,从图中看到现在已经有4个文件了。

通常情况下,生产环境的binlog会有成百上千个,这时候就需要确认我们需要的数据是在第几个binlog中了,下文也会讲怎么确定我们需要的是第几个

因为我们删库是刚刚发生的事情,所以我们需要的数据大概率是在第4个文件中

直接去查看第4个binlog文件,看到的全都是乱码,就像下面这样,这是因为binlog文件是二进制的

我们需要借助mysql官方提供的mysqlbinlog命令去才能正确解析binlog文件

用mysqlbinlog命令可以打开binlog文件,但是一个binlog文件的大小可能有几百兆,要从几百兆日志中找到我们需要的日志,还是比较麻烦的

还好mysqlbinlog命令提供一些参数选项可以让我们对binlog文件进行筛选,最常用的参数就是时间参数(下文也会对mysqlbinlog的详细用法进行说明)

经过和删库的研发人员确定,删库的时间大概是「10:40」,那我们就以这个时间点为参考,找前后5分钟的日志

 
 

mysqlbinlog -v --start-datetime='2021-06-10 10:35:00' --stop-datetime='2021-06-10 10:45:00' bin-log.000004 | grep t_user

编辑切换为居中

添加图片注释,不超过 140 字(可选)

从图中可以看到,这个时间点的日志确实包含我们删除数据的日志

接下来我们就需要把这些日志整理一下,然后想办法恢复到数据库就可以了。

首先,把我们需要的日志单独保存到tmp.log文件中,方便下载到本地

 
 

mysqlbinlog -v --start-datetime='2021-06-10 10:35:00' --stop-datetime='2021-06-10 10:45:00' bin-log.000004 > tmp.log

把tmp.log下载到本地,用文本编辑工具打开看一下,可以看到一堆伪sql

在上图的伪sql中 @1表示第一个字段 @2表示第二个字段 其他的以此类推

日志中包含的sql是一些伪sql,并不能直接在数据库执行,我们需要想办法把这些伪sql处理成可在数据库执行的真正的sql

我们使用的文本编辑工具的批量替换功能,就像下面这样

编辑切换为居中

添加图片注释,不超过 140 字(可选)

最终处理好的sql就像是这样

编辑切换为居中

添加图片注释,不超过 140 字(可选)

把处理好的sql在测试数据库验证一下没问题后直接在生产库执行

sql执行完以后,被误删除的数据就恢复回来了。

我们和删库的研发一起,把客户要求删除的6万多条数据重新给删除,算是完成了客户的要求

至此,删库事件就暂时告一段落。不要问删库的研发受到了什么处分,问就是什么处分都没有

几点建议

删库跑路真的不只是一句玩笑话,如果真的不小心删库了而又无法找回数据的话,不仅仅是简单的罚款、扣绩效就完事了,甚至有可能会面临牢狱之灾

对于公司来说,一个不小心的删库操作,就有可能把公司删没了。毕竟删库造成的数据损失、经济损失不是所有公司都有能力承担的

所以,生产环境的数据安全一定是重中之重。根据我多年的删库经历,也总结了一些经验分享给你们,希望对你们有所帮助

「1、研发人员不能直连生产库」

生产库一般由DBA或者运维来维护,研发人员很少有需要登录生产数据库查看数据的需求,就算数据真的有问题,一般情况下DBA或运维人员也能解决

如果一个系统需要研发人员频繁的登录数据库去维护数据,这时就该考虑在系统中增加一个管理功能来使用,而不是频繁登录数据库

所以,研发就不应该具有生产库的登录权限。如果偶尔的需要登录生产库查看数据,可以找DBA开一个临时账号

「2、登录生产库使用只读账号」

大部分人使用数据库都会使用连接工具,比如Navicat、SQLyog等

每个人的电脑上,大概率也只有一个连接工具。开发库、测试库、生产库都在同一个连接工具中打开,有时只是想在开发库中修改一条数据,却不小心修改了生产库

而MySql的事务是自动提交的,在连接工具中,正在修改的当前行失去光标后就会自动提交事务,极其容易操作失误

所以,如果确实的需要登录生产库,尽量使用具有只读权限的账号登录

「3、关闭autocomit、多人复核」

如果确实需要在生产库进行数据的增加、修改或删除,在执行sql之前最好先关闭事务的自动提交

在需要登录生产库修改数据的情况下,想必问题也比较复杂,一条sql语句应该是完成不了,可能需要写N多个sql才能完成数据的修改

这么多的sql,很有可能在执行的时候会选错。有时你只是想执行一个select语句,结果发现执行的是delete

更坑爹的是,大部分的数据库连接工具有执行当前选中内容的功能。有时候你只想执行当前选中的内容,结果发现执行的是全部内容

如果关闭了自动提交,就算出现上面的情况,也还有机会挽回。比如下面这样

 
 

-- 关闭事务自动提交 set @@autocommit=0; -- 查看需要删除的数据,共65600条 select * from t_user where age>18 and deptid=100; -- 删除 delete from t_user where age>18; -- 发现有问题,回滚 select * from t_user where age>18 and deptid=100; rollback ; -- 确认没问题,提交 -- commit;

另外,在commit之前需要至少再找一个同事进行确认。所谓当局者迷,自己有时可能处于一个错误的思路上,就想当然的认为结果没问题,这时就需要一个旁观者来指点迷津

两个人都确认没问题之后再提交,出错的机率也会小很多

「4、修改数据之前先备份」

备份、备份、备份,重要的事情说三遍

备份虽然会麻烦一点,但它是保证数据准确性最有效的手段

况且,掌握一些技巧后,备份也不是很麻烦的事情

比如,我们删除数据之前可以先这样备份

 
 

-- 创建一个和原表一样的备份表(包含索引) create table t_user_bak like t_user; -- 拷贝数据到备份表 INSERT into t_user_bak select * from t_user; -- 确认数据拷贝完成 select * from t_user_bak;

这样备份的数据,就算原表数据误删了,甚至都不用恢复数据,只需要把备份表的名字改成原表的名字直接使用就可以了

在生产库修改数据之前,一定要记得备份,一旦数据修改出错,这是成本最低并且最有效的恢复途径

「5、设置数据库定期备份」

生产环境,运维人员一定要设置数据库定期备份。研发人员也有义务提醒运维同事编写自动备份脚本,因为生产库一旦出现问题需要恢复数据,没有定期备份的话,麻烦的不只是运维人员,研发人员也要跟着麻烦

备份周期可以根据业务需要来决定。如果业务对数据要求的实时性比较高,备份周期相对短一点,恢复数据时可以最大程度的避免数据丢失;反之,备份周期可以长一点,节省磁盘空间

如果有必要,可以定期把备份文件拷贝到异地服务器,避免由于一些不可抗力因素导致的当前服务器磁盘损坏,如地震、台风等

binglog日志

binlog即Binary Log,它是二进制文件,用来记录数据库写操作的日志

数据库的insert、delete、update、create、alter、drop等写入操作都会被binlog记录

因此,数据库的主从数据同步通常也是基于binlog完成的,本文只对binlog做一些简单介绍,后期会单独写一篇文章讲基于binlog的主从数据同步

binlog日志需要配置开启,可以通过脚本查看binlog是否开启

 
 

SHOW VARIABLES LIKE 'LOG_BIN%';

编辑切换为居中

添加图片注释,不超过 140 字(可选)

如果log_bin参数显示的是OFF说明binlog是关闭状态,需要手动开启

开启binlog需要修改数据库的my.cnf配置文件,my.cnf文件通常在服务器的/etc目录下

打开/etc/my.cnf文件,配置binlog的相关参数,下文配置binlog的常用参数

 
 

# 启用binlog并设置binlog日志的存储目录 log_bin = /var/lib/mysql/bin-log # 设置binlog索引存储目录 log_bin_index = /var/lib/mysql/mysql-bin.index # 30天之前的日志自动删除 expire_logs_days = 30 # 设置binlog日志模式,共有3种模式:STATMENT、ROW、MIXED binlog_format = row

binlog的日志有三种格式,分别是STATEMENT、ROW、MIXED。在mysql5.7.7版本之前默认使用的是STATEMENT,之后的版本默认使用的是ROW

ROW格式

ROW格式下,binlog记录的是每一条数据被修改的详细细节。

比如,执行delete语句,删除的数据有多少条,binlog中就记录有多少条伪sql

 
 

delete from t_user where age>18;

那么row格式的日志的缺点就很明显,在发生批量操作时,日志文件中会记录大量的伪sql,占用较多的磁盘空间

尤其是当进行alter操作时,每条数据都发生变化,日志文件中就会有每一条的数据的日志。此时,如果表中的数据量很大的话,日志文件也会非常大

在mysql5.6版本之后,针对ROW格式的日志,新增了binlog_row_image参数。

当binlog_row_image设置为minimal时,日志中只会记录发生改变的列,而不是全部的列,这在一定程度上能减少binlog日志的大小

虽然记录每行数据的变化会造成日志文件过大,但这也是它的优点所在

因为它记录了每条数据修改细节,所以在一些极端情况下也不会出现数据错乱的问题。在做数据恢复或主从同步时能很好的保证数据的真实性和一致性

STATEMENT格式

STATEMENT格式下,日志中记录的是真正的sql语句,就像是这样

编辑切换为居中

添加图片注释,不超过 140 字(可选)

日志中的sql是直接可以拿到数据库运行的

STATEMENT格式的日志的优缺点和ROW格式的正好相反,它记录的是sql语句和执行语句时的上下文环境,而不是每一条数据。所以它的日志文件会比ROW格式的日志文件小一些

由于记录的只是sql语句和上下文的环境,STATEMENT格式的日志在进行主从数据同步时会有一些不可预估的情况出现,导致数据错乱。比如sleep()、last_insert_id()等函数会出现问题

MIXED格式

MIXED格式是STATEMENT和ROW的结合,mysql会根据具体执行的sql语句,来选择合适的日志格式进行记录

MIXED格式下,在执行普通的sql语句时会选STATEMENT来记录日志,在遇到复杂的语句或函数操作时会选择ROW来记录日志

mysqlbinlog命令

mysql数据库的binlog文件是二进制的,基本看不懂,使用数据库自带的mysqlbinlog命令可以把二进制文件转换成能看懂的十进制文件

由于数据库的binlog文件可能会很大,查看起来会很麻烦,所以mysqlbinlog命令也提供了一些参数可以用来筛选日志

「mysqlbinlog语法」

 
 

mysqlbinlog [options] log-files

options:可选参数 log-files:文件名称

「options的常用值」

-d: 根据数据库的名称筛选日志 -o:跳过前N行日志 -r, --result-fil: 把日志输出到指定文件 --start-datetime: 读取指定时间之后的日志,时间格式:yyyy-MM-dd HH:mm:ss --stop-datetime: 读取指定时间之前的日志,时间格式:yyyy-MM-dd HH:mm:ss --start-position: 从指定位置开始读取日志 --stop-position: 读取到指定位置停止 --base64-output:在row格式下,显示伪sql语句 -v, --verbose:显示伪sql语句,-vv可以为sql语句添加备注

「常用写法」 查看fusion数据库的日志

 
 

mysqlbinlog -d=fusion bin-log.000001

查看某个时间段内的日志

 
 

mysqlbinlog --start-datetime='2021-06-09 19:30:00' --stop-datetime='2021-06-09 19:50:00' bin-log.000001

恢复数据,事件的开始位置是4300,结束位置是10345

 
 

mysqlbinlog --start-position 4300 --stop-position 10345 bin-log.000001 | mysql -uroot -p123456 fusion

                                          资源获取:

大家点赞、收藏、关注、评论啦 、查看👇🏻👇🏻👇🏻微信公众号获取联系方式👇🏻👇🏻👇🏻

 精彩专栏推荐订阅:下方专栏👇🏻👇🏻👇🏻👇🏻

每天学四小时:Java+Spring+JVM+分布式高并发,架构师指日可待

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【专栏】实践篇08| All in docker!动手搭建Redis集群

关注公众号:【离心计划】,一起逃离舒适圈 Redis专栏合集 【专栏】01| Redis夜的第一章 【专栏】基础篇02| Redis 旁路缓存的价值 【专栏】基础篇03| Redis 花样的数据结构 【专栏】基础篇04| Redis 该怎么保证数据不丢失(上&#xff09…

(附源码)Spring Boot的网上作业管理系统 毕业设计 612317

基于Spring Boot的网上作业管理系统 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现…

【正点原子FPGA连载】第三十三章OV5640摄像头HDMI显示实验 摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第三十三章OV564…

02-Neo4j-CQL

02-Neo4j-CQL: 1、CQL简介 CQL代表Cypher查询语言。 像Oracle数据库具有查询语言SQL,Neo4j具有CQL作为查询语言。 Neo4j CQL 它是Neo4j图形数据库的查询语言。它是一种声明性模式匹配语言它遵循SQL语法。它的语法是非常简单且人性化、可读的格式。 …

具有成本效益的深度信任网络的智能LEACH的多级动态优化(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 💥1 概述 能量利用率是能量受限无线传感器网络(WSN)的关键属性,它直接影响网络的寿命。LEACH&#x…

C++入门篇之 注释语法什么写

📒博客主页: ​​开心档博客主页​​ 🎉欢迎关注🔎点赞👍收藏⭐留言📝 📌本文由开心档原创! 📆51CTO首发时间:🌴2022年12月12日🌴 ✉…

python+requests接口自动化测试框架实例详解教程

前段时间由于公司测试方向的转型,由原来的web页面功能测试转变成接口测试,之前大多都是手工进行,利用postman和jmeter进行的接口测试,后来,组内有人讲原先web自动化的测试框架移驾成接口的自动化框架,使用的…

windows下Qt 5的安装与编译打包

环境与版本 操作系统:windows 10 Qt版本:5.14.2,最后一个有独立安装包的版本,下载地址:archive/qt/5.14/5.14.2 IDE:自带的qt-creator 4.11.1,也可以自行下载其他版本4.14.2,下载…

Mybatis实现增删改查

准备工作:建立项目,连接数据库MySQL,安装Mybatix插件 数据库代码准备: -- 删除tb_brand表 drop table if exists tb_brand; -- 创建tb_brand表 create table tb_brand (-- id 主键id int primary key auto_increment,…

itop3568开发板旋转uboot logo和内核logo

修改设备树 rk_android11.0_sdk/kernel/arch/arm64/boot/dts/rockchip/topeet_rk3568_lcds.dtsi 文件。如果配套的屏幕是 LVDS 7 寸屏幕或者 LVDS10.1 寸 1024*600 屏幕或者 LVDS10.1 寸 1280*800 屏幕,修改如下所示。 &route_lvds{ status "okay"; …

使用Postman+JMeter进行简单的接口测试

以前每次学习接口测试都是百度,查看相关人员的实战经验,没有结合自己公司项目接口真正具体情况。 这里简单分享一下公司项目Web平台的一个查询接口,我会使用2种工具Postman和JMeter如何对同一个接口做调试。 准备工作 首先,登录公…

GATK Germline_SNP_INDEL_2.0 分析遗传病(耳聋)

GATK Germline_SNP_INDEL_2.0 分析遗传病(耳聋) 一、本文是Gatk Germline spns-indels Pipeline 分析遗传病(耳聋)的升级版,目的是提供开箱即用的分析流程,尽可能简化部署和迁移。 更新内容如下: 人类参考基因组以及…

RTSP 媒体协议流的录制方案及其覆盖策略详解

前言 在安防和监控领域,RTSP 媒体协议流有很广泛的使用。本文将介绍一种针对 RTSP 媒体流的录制方案及其相应的覆盖策略。据我所知,声网的实时录制功能支持三种模式,分别是云端录制、本地服务端录制和页面录制,今天我们介绍的录制…

[基因遗传算法]进阶之六:VRP的进阶经典问题的解码如何写

文章目录一、CVRP二、MDCVRP2.1 解的编码分析2.2 代码2.3 分割展示三、VRPTW四、MDVRPTW4. 1 解的编码分析4.2 解的代码4.3 结果展示4. 4 MDVRPTW的计算适应度4.5 MDVRPTWd的结果展示图一、CVRP 见博文《[基因遗传算法]进阶之三:实践CVRP》 二、MDCVRP 参考资料:《Python实现…

Qt的场景图Scene Graph

叫场景树更合适,本质不是图。QML场景中的Qt Quick项目将填充QSGNode实例树。 场景图是Qt Quick 2.0引入的,建立在要绘制的内容是已知的基础上。所有QML项目均使用场景图进行渲染,场景图的默认实现是与OpenGL紧密相关的低级高性能渲染堆栈。 …

谈谈前端性能优化-面试版

前言 当我们去面试的时候,很大概率会被面试官问这么一个问题:你有尝试过对项目做性能优化吗?或者你了解哪些性能优化的方法?听到这个问题的你可能是这样的: 似曾相识但又说不清楚,往往只能零散地说出那么几…

Go string原理简析

引入 当查看string类型的变量所占的空间大小时,会发现是16字节(64位机器)。 str : "hello"fmt.Println(unsafe.Sizeof(str)) // 16也许你会好奇,为什么是16字节,它的底层存储模型是什么样子的。 源码分析 …

焦脱镁叶绿酸-a修饰量子点/荧光/药物/小分子抑制剂/上转换纳米颗粒/树枝状聚合物

小编在这里为大家分享的科研内容是焦脱镁叶绿酸-a修饰量子点/荧光/药物/小分子抑制剂/上转换纳米颗粒/树枝状聚合物的相关研究,来看! 焦脱镁叶绿酸-a简介: 焦脱镁叶绿素-a是产物叶绿素a通过脱甲氧羰基、去植物醇、去Mg后的产物。该类物质具有…

day19【代码随想录】删除字符串中的所有相邻重复项、逆波兰表达式求值、滑动窗口最大值、前 K 个高频元素、数组中的第K个最大元素

文章目录前言一、删除字符串中的所有相邻重复项(力扣047)二、逆波兰表达式求值(力扣150)三、滑动窗口最大值(力扣239)四、前 K 个高频元素(力扣347)五、数组中的第K个最大元素&#…

MyBatis系列---crud返回值

目录1. service与mapper2. 更新操作3. 查询操作3.1. 返回值存储3.2. 简单映射3.3. ResultSet 的预处理3.4. 确定 ResultMap3.5. 创建映射结果对象3.6. 自动映射3.7. 存储对象3.8. 返回结果为单行数据3.9. 返回结果为多行数据3.10. 结论1. service与mapper mybatis一般与spring…