场景
数据库中有张企业表,这个表里的删除字段 isdelete 给了默认值0,但开发在处理代码时编写的插入语句中带了这个 isdelete 字段,并且给了 Null 值,导致用户填写企业信息时失败,从而导致更新用户关联企业时这个用户的企业被更新为 Null。
与此同时后台操作人员又进行了一个操作,这个操作的大致步骤是,按照这个用户的所在企业查询相关用户并进行删除,但由于这个用户的企业是 Null 同时查询处理是个通用的方法对 Null 处理进行了跳过,最终导致查询结果是所有用户,接着令人恐怖的一幕发生了,这张表中的所有用户都被删除。
发现这个问题后,我的第一想法是,因为这张数据表的写入并不多,可以先按照更新时间来进行数据恢复,然而由于这张表历史比较久远,当时并没有对这个表的更新时间字段做变更自动更新,导致这个方法行不通。所以只能通过 binlog 来恢复。
基于数据库使用的是阿里云的 RDS 所以恢复过程还是比较顺畅的。
操作
1、创建数据追踪工单
选择对应的数据库、数据表,输入被误删的数据表表名,追踪类型选择更新,再根据报异常的时间设置时间范围。
生成后在工单详情可看到该时间范围内的变更数据记录,在变更时间列发现大量数据都在同一个时间范围内出现更新,因为该表的更新频次很低,所以我们可以根据这个变更时间来确定恢复数据的范围。
点击上图中的查看详情,可以看到具体变更的字段是哪些:
由此即可确定误删数据了。
2、修复数据
在工单内点击导出回滚脚本,然后根据脚本进行数据回滚。以下简单举例下脚本的内容:
UPDATE `database`.`table` SET `id`=5510 , #...此处省略若干表中的字段... `isdelete`=0 WHERE (`id`=5510);
回滚的脚本就是按照数据表中的主键来将数据恢复到修改之前的样子,从上面的语句可以看到,在恢复的语句中已经将 isdelete 这个字段设置为 0 了。这个语句中还会包含其他的字段,此处我在恢复数据时,并没有将其他字段也放到 update 语句中,只做了 isdelete 字段的恢复。
使用修改后的 SQL 提交数据变更工单即可将数据恢复。
总结
1、线上问题处理思路
碰到线上问题,我们应该第一时间去用最快并且质量有保障的办法解决问题,然后再追查原因,定责。比如本次事故中,优先恢复数据,再确定产生问题的原因,解决 bug 并发布。
- 确定出现问题的时间
- 根据业务的情况,确定数据恢复方案
- 根据问题时间查找接口访问日志,确定问题接口
- 由问题接口确认业务影响的范围,改正问题
2、开发设计思路
- 数据表的创建时间、更新时间、是否删除字段设置为插入默认值,更新时间为根据当前时间戳更新
- 设计到数据删除的代码,需要做严格的校验,当数量超过一定范围时需要进行提示阻断
- 开发在开发环境调试时,应该做数据 sql 自检查