现象
应用MySQL Connector/J(mysql-connector-java)升级,由5.1.20升级到5.1.30。
灰度发布后,发现查询功能异常,按照时间查询不到之前创建过的订单了。
private Date searchDate;
对应查询SQL如下所示:其中MySQL中order_tbl表中的create_timestamp字段为TimeStamp类型。
select * from order_tbl where create_timestamp = #{searchDate}
排查过程
一、打印SQL参数
打印下SQL中的searchDate查询参数,判断异常机器和正常机器是否一致。
缩小排查范围。如果不一致,大概率是应用层哪块处理不一致导致的问题;反之基本可以确认是数据库驱动或者数据库层面的问题(因为本次也升级了MySQL Connector/J的版本)。
项目使用的是Mybaits ORM框架,这里直接是打开了Mybaits输出sql语句的配置。
发现灰度异常机器和正常机器输出的SQL参数 searchDate 是一致的,如:2020-01-29 09:21:31.031,都是带有小数位的。
结合应用变更,基本可以断定是由Connector/J版本升级导致的。
二、MySQL Connector/J Release Notes
查下对应版本的Release Notes。
发现在5-1-23版本Release Notes里有一项BugFix
The nativeSQL() method would always truncate fractional seconds rather than preserving the fractional part in the output string. Now Connector/J checks the server version: it preserves the fractional part for MySQL 5.6.4 and greater, and truncates the fractional part for older versions. (Bug #14748459, Bug #60598)
大意是:修改了nativeSQL方法,低版本Connector/J发给数据库的时间是秒级别的,小数秒位会被丢弃。
本次修改,如果MySQL server版本大于等于5.6.4,将会保留这个小数秒。(这也是查询异常的原因,DB里面的历史数据是不带小数秒的,查询的时候是以小数秒查询,必然是查询不出来的)
对应的代码变更如下:
https://github.com/mysql/mysql-connector-j/compare/5.1.22…5.1.23

为什么是5.6.4版本?
MySQL 5.6 has fractional seconds support for TIME, DATETIME, and TIMESTAMP values, with up to microseconds (6 digits) precision:
https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
解决方案
方案1:设置create_timestamp字段小数精度优点:彻底解决问题;缺点:影响面比较大,数据整体都会受影响。
方案2:业务上看是否能去除类似的查询,尤其是时间类型的字段,受版本影响比较大,不建议作为严格匹配的条件。
方案3:查询前对searchDate进行强制转化,去除掉小数位。存在代码改动,并且改动不彻底。不建议。
方案4:jdbc驱动使用老模式解析timestamp















