- 跟踪问题原因
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())));
}```
网友评论