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

2020-06-08  本文已影响0人  matthewfly
  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())));
    }```
上一篇下一篇

猜你喜欢

热点阅读