跑路代码已上线,坐等删库中~

前言

或许大家会认为删库跑路都是运维或者DBA的事情,或许认为我没有线上数据库权限就不可能删库跑路。但是事实并非如此,建议大家仔细阅读此文章,赶紧排查下您的代码,很可能隐藏着这种删库程序。还是要呼吁大家,这个案例大家不要学习!不要学习!不要学习!重要的事情说三遍。

业务BUG现象

最近,我们收到一位研发小伙伴的反馈,他发现了一项safety级别的bug,仅仅是执行了一个简单的数据删除操作,就差点把几百万业务流转表数据全部删除了,要是被老板知道妥妥的被劝退!马上就打算跑路了,好在及时才避免严重后果的发生。究竟发生了什么?让我们在回顾一下这位小伙伴所遭遇的问题。

开发业务需求

需求是要根据业务任务流转ID进行软删除,然后通过定时任务定期清理,于是该研发同学写了下面一个方法代码来进行此操作。以下为抽象后的代码逻辑:

//业务流转任务更新
public void updateTaskError(long taskId) throws SQLException {
    String updateSql = "UPDATE business_task SET status = '0' WHERE task_id = ?";
    try (PreparedStatement pstmt = connection.prepareStatement(updateSql)) {
        pstmt.setInt(1, taskId);
        pstmt.executeUpdate();
    }
}

//定时任务定期清理
public void deleteErrorTask() throws SQLException {
    String deleteSql = "DELETE FROM business_task WHERE status = 0";
    try (PreparedStatement pstmt = connection.prepareStatement(deleteSql)) {
        pstmt.executeUpdate();
    }
}

更新逻辑本身很简单,code review没看出问题,自测由于定时任务没有触发,所以也没有发现问题。但到了测试手里,却发现数据全没了,这要是发布到了线上,后果将非常严重!

开发同学自查,到底哪条SQL导致?

开发本地开启SQL打印后,复现场景,是这样一条SQL:

DELETE FROM business_task WHERE status = 0;

该业务任务表的status一般取值为枚举类型,比如running、success等,这里的0表示任务异常,需要进行清除。看起来这条SQL语句会清理掉异常任务,没啥问题!难道是SQL发生了隐式转换导致的?

隐式转换问题,好坑呀!

MySQL官方文档翻一翻,这个SQL为何会有隐式转换呢?

# 这里是官方文档关于隐式转换浮点数比较规则
In all other cases, the arguments are compared as floating-point (double-precision) numbers. For example, a comparison of string and numeric operands takes place as a comparison of floating-point numbers.

上面的大致解释:MySQL 会尝试从字符串中解析尽可能多的有效数字,直到遇到非数字字符或者无法继续形成有效的浮点数:
1)如果字符串无法转换为有效的浮点数,MySQL将返回0
2)字符串以浮点数字开头,将截取出有效的浮点数,例如:

  • ‘123.45xyz’ -> 123.45
  • ‘xyz123’ ->0

在MySQL中执行手动验证转换规则:

mysql> select CAST('123.45xyz' as DECIMAL(10, 2));
+-------------------------------------+
| CAST('123.45xyz' as DECIMAL(10, 2)) |
+-------------------------------------+
|                              123.45 |
+-------------------------------------+
1 row in set (0.00 sec)


mysql> select CAST('xyz123' as DECIMAL(10, 2));
+----------------------------------+
| CAST('xyz123' as DECIMAL(10, 2)) |
+----------------------------------+
|                             0.00 |
+----------------------------------+
1 row in set, 1 warning (0.00 sec)

验证后确实和上面规则中的结果一致,那业务SQL是如何触发隐式转换的呢?我们进一步进行分析。

原始业务SQL如何转换?

分析代码,发现业务SQL中的status含有非数字开头的字符串,按照隐式转换会转变成0,实际内部转换的大致如下:

DELETE FROM business_task WHERE cast(‘success’ as unsigned) = 0;

那么当定时任务触发时,在MySQL5.6版本的数据库上执行该SQL,相当于全表进行了删除,至此,业务bug已定位完成,只需将0改成’0’即可解决问题。

如何利用DBdoctor快速定位隐式类型转换?

使用DBdoctor,只需两步即可完成SQL审核的隐式转换检测:

Step 1:点击【实例诊断】

登录DBdoctor点击【实例列表】,选择对应的租户项目,找到系统涉及的实例,然后点击【实例诊断】

在这里插入图片描述

Step 2:查看【SQL审核】,输入业务SQL,点击审核:

批量上传待审核的SQL(可从测试环境导出)或者输入指定SQL,点击审核即可。

在这里插入图片描述

查看结果,发现该SQL存在隐式类型转换问题,及时处理问题SQL。

总结

各位研发小伙伴们,你们是否也会经常遇到类似问题,因为执行了一条不当的SQL更新语句,就险些造成了灾难性的数据故障!为避免这些不必要问题的发生,马上部署DBdoctor,使用SQL审核功能,快速识别潜在问题,无需生产发布和变更,就能提前评估SQL语句在实际部署后可能遇到的性能问题,并推荐最佳的全局索引策略,以确保数据库操作的高效和安全。

DBdoctor推出长久Free版
DBdoctor是一款企业级数据库全方位性能监控与诊断平台,致力于解决一切数据库性能问题。可以对商业数据库、开源数据库、国产数据库进行统一性能诊断。
图片具备:SQL审核、巡检报表、监控告警、存储诊断、审计日志、权限管理等免费功能,不限实例个数,可基于长久免费版快速搭建企业级数据库监控诊断平台。
图片同时拥有:性能洞察、锁分析、根因诊断、索引推荐、SQL发布前性能评估等高阶功能,官网可快速下载,零依赖,一分钟快速一键部署。
如果您想要试用全部功能可添加公众号自助申请专业版license。成为企业用户可获得产品定制、OpenAPI集成、一对一专家等高阶服务。欢迎添加小助手微信了解详细信息!

免费下载/在线试用
https://dbdoctor.hisensecloud.com/col.jsp?id=126

公众号:DBdoctor
如果您是开发或DBA欢迎关注公众号,关注公众号回复:“进群”,可拉您进入技术交流群。
在这里插入图片描述

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值