1. offer 收割机,开启职场新篇 回溯至五年前,就业市场一片繁荣,我历经多轮面试,收获颇丰,收到了很多 offer。最终,我选择了一家互联网教育的创新企业。这家公司的福利体系令人艳羡,不仅零食无限量供应,还能享受准时下班的惬意,一切远超我的预期,内心不禁暗自庆幸:“可算让我找着神仙公司了。” 在熟悉环境之后,我趁着上厕所的时候,顺便去旁边的零食摊挑了点零食。接下来的一天里,我全身心投入到开发环境的搭建与新人文档的研读中,当然,手边的零食也成了不可或缺的陪伴。 入职几天后 ,领导分配给我一个小型项目。与同事深沟通完技术方案后,就开始开发了。
2.单元测试奇遇项目开发完毕,我开始着手单元测试。但是这里的测试风格却与我之前经历的截然不同。 这家公司的单测好像没有启动整个项目,仅加载了部分类,而且不能访问测试环境数据库~ 于是我决定按照前东家写单测的方式重新写单元测试。 我新建了测试基类,启动整个 Spring Boot 应用,直接访问测试数据库。但这一尝试却让我陷入了异常的泥潭,好在项目时间充裕,我耐心排查,逐一解决。 我做梦也没有想到,此刻,已经铸成大错。
3.故障现场正当我沉浸于单元测试的调试中时,周围的工位慢慢聚集起了越来越多人,讨论声此起彼伏,吸引了我的注意。 “测试环境怎么这么多异常,到处都是 500 报错?” 不知道谁在说话。 “我们正在排查,请稍候。” 我旁变的同事一边查阅日志,一边耐心回复。 “数据库怎么报错说找不到数据?” 另一位同事小声嘀咕,然后打开了 MySQL 命令行界面。 我目睹了他的一系列操作,奇怪的是数据库表里的数据全部被删掉了,其他的几个表数据也都被删除了。 此刻的我还处于吃瓜心态。 正当我心存疑惑,猜测这一切是否与我的单元测试有关时,又迅速否定了这一想法,毕竟我只是在调试,又没有执行任何可能删除数据的操作。我还在笑话自己 胡思乱想…… 很快 DBA 就抱着电脑过来,指着电脑说,你们看这些日志,确实有人把这些表删除了。 "有 IP 吗,定位下是谁删除的, 另外线上环境有问题吗?”,旁边的大组长过来和 DBA 说。 “嗯,我找到 ip 了,我找运维看下,这个 ip 是谁的”。DBA 回复道。
4.澄清真相的艰难时刻当 DBA 将怀疑的目光投向我时,我内心充满了无辜与困惑。我自己并没有触碰任何可能引发此问题的代码,甚至开始怀疑自己是否成了某种误解的牺牲品。(他们知道我刚入职,我现在怀疑:那一刻他们可能会怀疑 我是友商派过来的卧底、间谍,执行删库的秘密任务) 经过一系列深入的分析与讨论,真相最终浮出水面——确实是我所添加的单元测试,由于配置不当,意外触发了数据库的清理脚本。
5.事故根源剖析需要明确的是,原有的单元测试框架与测试环境启动机制均不会主动删除数据库数据。 然而,一旦单元测试连接到测试数据库,便会触发一场数据浩劫。
5.1 单元测试为何成为 “数据杀手”?原单元测试采用的是 H2 内存数据库,它作为 Java 的一个嵌入式数据库,非常适合单元测试场景。但问题在于,公司提供的 SQL 脚本中包含了先删表后建表的逻辑,以确保脚本的可重复执行性。当我的单元测试错误地将 H2 数据库替换为测试数据库时,这场灾难便悄然上演。
5.2 测试数据库为何执行了 “自杀” 脚本?原因在于我新建的单元测试更改了数据库配置,且 spring.data.initialize 默认为 true,导致测试数据库在启动时自动执行了包含删表语句的 SQL 脚本。
5.3 为何正常启动测试环境时无恙,不会删除所有数据呢?因为测试目录下的文件与正式代码编译后的结果是分离的,所以正常启动测试环境时,不会执行到测试目录下的 SQL 脚本。
6.惨痛的教训与未来的防范虽然数据最终通过 DBA 的备份得以部分恢复,但仍有一部分数据因快照非实时而永久丢失。幸运的是,这只是测试环境,没有对生产环境造成影响。 为防微杜渐,我们采取了以下措施: ● 严格限制数据库账户的权限,确保只有管理账户能修改表结构。 ● DBA 加强测试数据库的快照管理,缩短快照间隔,并研究删库后的快速恢复方案。 ● 将所有项目的 spring.data.initialize 设置为 false,避免自动执行 SQL 脚本。 ● 禁止 SQL 脚本中包含删表语句,寻找其他方法解决脚本重复执行的问题。 ● 另外的一个项目急需人手,把新来的那谁 调到其他项目上。 这可能是程序员们在技术上越来越保守的原因……不经意的一个调整可能引发无法承受的滔天巨浪 |