1. 起因
最近在工作中遇到了一个问题,某一块代码如下:
代码片段1:
SELECT
COUNT(*)
FROM
test_table
WHERE
id = ${id}
AND status NOT IN (3, 4);
这段代码用于查询一个表中某个id下未被删除的数据条数。这是一个我们很常见的业务场景,也很简单,但是某一天某个同事在和我一起写相关的代码时,产生了疑问。
自己曾和我说:“我们之前一直以为它是没问题的,但是我之前却发现有的数据没有查出来。”
这个问题让我感到十分困惑,我们查找数据的时候没有任何限制,不应该出现漏查的情况。于是,我们开始尝试从不同的方向去解决这个问题。
2. 排查过程
2.1 数据库连接问题
我们首先怀疑是数据库连接问题,于是我们检查了数据库的连接情况,看看是否有数据库连接超时的情况,但是我们的数据库连接池配置足够用,而且从数据库服务器的日志上也没有发现连接超时的情况。
2.2 系统时间问题
因为我们有个定时任务会把表中的一些状态由未开始变为进行中,我们随机找了一些未查询到的数据进行比对,发现且只有最近一周左右的数据才会出现查不到的情况。因此,我们怀疑可能是因为系统时间不同步导致的问题。我们通过命令行查看系统时间,但是发现没有出现时间差异的情况。
2.3 sql语句问题
我们甚至怀疑是sql语句的问题,我们分析发现不同于其他的sql,这段sql使用的是NOT IN 操作符,会导致一些隐式转换,当字段为null或者不存在时,会导致结果不被过滤掉。
我们执意认为sql语句没问题,因为它已在我们的系统中执行多年,并一直保持着正常的工作状态。但是,我们还是花了几个小时检查了业务逻辑,也没有发现任何问题。
3. 最终答案的揭示
当我们已经准备放弃的时候,不经意间我发现系统日志中出现了一条错误信息:
错误日志:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.xxx.mapper.TestMapper.getTestCount
是的,问题是出在了mybatis的映射文件中,我们在sql语句前少写了两个‘-’,导致sql语句没有正确的被解析出来。而这个问题一直没有暴露出来是因为我们项目中默认的日志级别是ERROR,而这种情况只是WARN级别。
4. 总结
这个小问题教会了我们许多,包括发现问题不要想当然,需要一步步的排查问题。
同时,我们还要重视日志的作用,一个令人困惑的数据问题背后,日志可能会给出正确的方向。
最后,我们通过这个问题还了解了NOT IN语句在null值下的不同表现,这也让我们更深入的理解了这个操作符。