1. 问题
诡异的问题表象: 前端反馈分页接口的Total字段一直为0
使用Visualvm中的 Profiler 注入到应用后,查看JDBC监控得到了分页接口执行的SQL,复制出来执行是55. 此时还没有注意到 IN 的范围中有一个特别的值 'NULL'
🤨
2. 排查
开始查使用到的Mybatis plus分页插件是不是有bug,debug一轮发现SQL执行的结果就是0 然后才赋值给的IPage对象 😢 这下更奇怪了
重放请求,继续! 往JDBC执行SQL的入口去找,就不信是DataGrip的问题,然后在MySQL的驱动中发现 com.mysql.cj.NativeSession#execSQL 执行的SQL是 SELECT COUNT(*) ... id NOT IN (null, 128, 129)
emmm 迷茫🤨
根据MySQL官方文档所描述 operator IN() 可以确认这个 id not in 子句永远会返回null 所以不会有符合条件的数据 count为0。
To comply with the SQL standard, IN() returns NULL not only if the expression on the left hand side is NULL,
but also if no match is found in the list and one of the expressions in the list is NULL.
好了,只要在应用代码中加个过滤空问题就解决了🤣
又是一个低级错误导致表象看起来不可思议问题的案例
问题又来了,为什么visualvm中监控到的SQL是 in ( 'NULL' )
呢 😟
看了下这个项目大部分是Java代码,拉他代码瞅瞅,拉下来发现是古早的ant项目,emmm 在IDE中调试的想法直接放弃,转而从GUI入手, 找到这个界面对应的代码 ProfilerJDBCPanel
但是由于没构建,只能手动搜文件和字符串去找调用关系,总所周知项目中SQL的执行基本都是用PreparedStatement, 传入的只有模板和参数,真实SQL是驱动构建的,visualvm 同样要走这一步。
看了一会发现一个可疑的方法 org.graalvm.visualvm.lib.jfluid.results.jdbc.SQLStatement#getFullSql
。 通过 arthas watch 这个方法后,确认了是这里返回了错误的SQL。😓