美文网首页
mybatis Timestamp读出时间相差13小时问题

mybatis Timestamp读出时间相差13小时问题

作者: matthewfly | 来源:发表于2020-06-08 14:40 被阅读0次
    1. 跟踪问题原因
      mybatis 做数据类型转换时ResultSetImpl 默认的timestampe转换类为SqlTimestampValueFactory,该类初始化时,其timezone为 timezone(this.session.getServerSession().getDefaultTimeZone()),
      取的是默认的时区getDefaultTimeZone,该时区不是预想中的东八区时区,转换后相差13个小时。
    this.defaultTimestampValueFactory = new SqlTimestampValueFactory(pset, (Calendar)null, this.session.getServerSession().getDefaultTimeZone());
    

    2.查看mysql时区配置初始化过程
    mysql时区初始化在NativeProtocol中完成:

    public void configureTimezone() {
            String configuredTimeZoneOnServer = this.serverSession.getServerVariable("time_zone");
            if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
                configuredTimeZoneOnServer = this.serverSession.getServerVariable("system_time_zone");
            }
    
            String canonicalTimezone = (String)this.getPropertySet().getStringProperty(PropertyKey.serverTimezone).getValue();
            if (configuredTimeZoneOnServer != null && (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone))) {
                try {
                    canonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, this.getExceptionInterceptor());
                } catch (IllegalArgumentException var4) {
                    throw (WrongArgumentException)ExceptionFactory.createException(WrongArgumentException.class, var4.getMessage(), this.getExceptionInterceptor());
                }
            }
    
            if (canonicalTimezone != null && canonicalTimezone.length() > 0) {
                this.serverSession.setServerTimeZone(TimeZone.getTimeZone(canonicalTimezone));
                if (!canonicalTimezone.equalsIgnoreCase("GMT") && this.serverSession.getServerTimeZone().getID().equals("GMT")) {
                    throw (WrongArgumentException)ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("Connection.9", new Object[]{canonicalTimezone}), this.getExceptionInterceptor());
                }
            }
    
            this.serverSession.setDefaultTimeZone(this.serverSession.getServerTimeZone());
        }
    

    其中time_zone为mysql全局配置变量;system_time_zone为读取的系统时区;canonicalTimezone为配置的mysql链接中serverTimezone参数。因此可以有两种解决方法:
    a,mysql链接加上参数:serverTimezone=GMT%2B8。
    b,修改mysql时区配置。

    3.为何mysql读取默认时区不是东八区?
    mysql初始化时读取系统时区配置并保存到system_time_zone,以本机为例,系统时区为cst。java的calendar保存的cst对应的不是中国时区,而是美国时区。该常量在ZoneInfoFile中:

    {"CST", "America/Chicago"}
    

    导致了时间相差13个小时。

    4.其他解决方法
    如果避开mybatis的Timestamp类型转换就可以避免时区问题。将mybatis实体类中Timestamp类型字段定义string类型,类型转换时直接返回数据库中时间。string对应的类型转换类是StringValueFactory,转换timestamp代码如下:

        public String createFromTimestamp(InternalTimestamp its) {
            return String.format("%s %s", this.createFromDate(its), this.createFromTime(new InternalTime(its.getHours(), its.getMinutes(), its.getSeconds(), its.getNanos())));
        }```
    

    相关文章

      网友评论

          本文标题:mybatis Timestamp读出时间相差13小时问题

          本文链接:https://www.haomeiwen.com/subject/owrltktx.html