Mysql时间精度丢失问题

    这两天发现一个问题,在数据库中使用了DateTime(3)类型的字段,但是发现本地的ide中入库的数据,所有的毫秒数为000,只能精确到秒,但是dev环境的服务器却是可以精确到正常的毫秒数。由于代码包和数据库都是相同的,问题难以排查,所以直接进行了跟踪源码进行排查。发现最后的原因,是本地的mysql-connector-java版本是5.1.15而服务器上面是5.1.45,版本不同导致的问题。mysql-connector-java这个jar包在5.1.22及以下的版本中存在一个Bug,会将时间精度丢失,5.1.23及以上版本修复了这个bug。

下面看下源码中产生Bug的地方,PrepareStamtement.setTimestampInternal

private void setTimestampInternal(int parameterIndex, Timestamp x, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws SQLException {
        if (x == null) {
            this.setNull(parameterIndex, 93);
        } else {
            this.checkClosed();
            if (!this.useLegacyDatetimeCode) {
                this.newSetTimestampInternal(parameterIndex, x, targetCalendar);
            } else {
                String timestampString = null;
                Calendar sessionCalendar = this.connection.getUseJDBCCompliantTimezoneShift() ? this.connection.getUtcCalendar() : this.getCalendarInstanceForSessionOrNew();
                synchronized(sessionCalendar) {
                    x = TimeUtil.changeTimezone(this.connection, sessionCalendar, targetCalendar, x, tz, this.connection.getServerTimezoneTZ(), rollForward);
                }

                if (this.connection.getUseSSPSCompatibleTimezoneShift()) {
                    this.doSSPSCompatibleTimezoneShift(parameterIndex, x, sessionCalendar);
                } else {
                    synchronized(this) {
                        if (this.tsdf == null) {
                            this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US);
                        }
                        //这里将精度丢失了,mysql-connector-java <=5.1.22 都会有这个问题,当然如果采用ServerPrepareStatement不存在这个时间转换,也就不会存在这个问题了,如果采用5.1.22以上的版本,这个bug修复之后同样也不会存在这个问题
                        timestampString = this.tsdf.format(x);
                        this.setInternal(parameterIndex, timestampString);
                    }
                }
            }

            this.parameterTypes[parameterIndex - 1 + this.getParameterIndexOffset()] = 93;
        }

    }

这里还提供一种方式,采用设置useServerPrepStmts=true也可以解决这个问题,但是useServerPrepStmts=true获取的是ServerPrepareStatement,不是PrepareStatement,并且useServerPrepStmts=true这个参数在Mysql5.7.22以下的版本中存在一个bug,即union all 中包含Date类型的字段的时候会抛异常,官方bug:https://bugs.mysql.com/bug.php?id=87534 ,所以建议一般设置成false(默认值也是false)

转载于:https://my.oschina.net/guanhe/blog/3020004

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值