1、背景
由于项目需要,需要将mysql数据库切换到maria数据库。
2、问题
将数据库切换到maria后,发现数据库dateTime格式丢失了毫秒精度。
正常情况:
image.png
出现的问题:
image.png
发现丢失了毫秒精度。
3、解决
一开始以为是数据库格式的格式的问题,查看数据库格式后发现格式是datetime(3),保留3位毫秒数。是没有问题的。
image.png
后来直接操作数据库再次验证。
企业微信截图_16729034036544.png
发现是可以正确存储时间格式的。
且同过日志查看到执行的sql参数也是正确的
image.png
那精度为什么丢失了呢?既然数据库没问题,数据也没有问题,此时怀疑问题出现在驱动上,在查看数据库驱动时发现使用的驱动是driver-class-name: com.mysql.jdbc.Driver;虽然mysql驱动和maria驱动区别不大,但还是存在差异。
此时将数据库驱动更换为driver-class-name: org.mariadb.jdbc.Driver;再次执行操作,发现数据正常,毫秒精度得以保留。那说明问题的确出现在驱动上。
4、原因
虽然知道了驱动问题,但是根本原因是什么呢?
查看mysql驱动包源码,了解到时间戳的处理是在com.mysql.cj.ClientPreparedQueryBindings这个类中:
image.png image.png
在方法setTimestamp中通过this.session.getServerSession().getCapabilities().serverSupportsFracSecs()会去做精度的控制。
再看serverSupportsFracSecs()方法:是根据serverHasFracSecsSupport获取;
image.png
而serverHasFracSecsSupport是在com.mysql.cj.protocol.a.NativeCapabilities中:通过获取当前数据库serverVersion比较再来控制。当version版本低于5.6.4时,即会丢失精度。而这里获取到的版本号
image.png
通过debug得知我的获得的版本号是5.5.5,mysql驱动获取到的版本小于5.6.4,所以会忽略毫秒。
image.png
而在maria的驱动包中,我们通过源码发现在org.mariadb.jdbc.BasePreparedStatement类中处理了时间精度;
image.png
而这里的时间精度不会去和数据库版本号关联,也不会做丢失精度的处理。所以换了maria驱动包后,时间精度处理正常。
至于为什么获得的版本号是5.5.5?
实际上这是一个mariaDB的一个bug
参考:MariaDB 版本前缀“5.5.5-”未剥离 ·问题 #7972 ·PHP/PHP-SRC ·GitHub
网友评论