<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
问题:mysql-connector-java8导致java.util.Date时间入库mysql库相差13个小时
解决方案1:jdbc配置连接指定时区
#原有配置
#jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
#指定为东八区(北京时间)
jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=GMT%2B8
#或指定为上海时间
#jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
解决方案2:修改数据库时区(不推荐使用,可能会影响到其他程序)
#查询数据库时区
show variables like '%time_zone'
#在my.cnf文件里指定时区,添加下行代码
default-time_zone = '+8:00
原因
com.mysql.cj.jdbc.ConnectionImpl.initializePropsFromServer() throws SQLException {
...
this.session.getProtocol().initServerSession();
...
}
com.mysql.cj.protocol.a.NativeProtocol.initServerSession() {
configureTimezone();
...
}
com.mysql.cj.protocol.a.NativeProtocol.configureTimezone() {
String configuredTimeZoneOnServer = this.serverSession.getServerVariable("time_zone");
if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
configuredTimeZoneOnServer = this.serverSession.getServerVariable("system_time_zone");
}
String canonicalTimezone = getPropertySet().getStringProperty(PropertyKey.serverTimezone).getValue();
if (configuredTimeZoneOnServer != null) {
// user can override this with driver properties, so don't detect if that's the case
if (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone)) {
try {
canonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, getExceptionInterceptor());
} catch (IllegalArgumentException iae) {
throw ExceptionFactory.createException(WrongArgumentException.class, iae.getMessage(), getExceptionInterceptor());
}
}
}
if (canonicalTimezone != null && canonicalTimezone.length() > 0) {
this.serverSession.setServerTimeZone(TimeZone.getTimeZone(canonicalTimezone));
//
// The Calendar class has the behavior of mapping unknown timezones to 'GMT' instead of throwing an exception, so we must check for this...
//
if (!canonicalTimezone.equalsIgnoreCase("GMT") && this.serverSession.getServerTimeZone().getID().equals("GMT")) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("Connection.9", new Object[] { canonicalTimezone }),
getExceptionInterceptor());
}
}
this.serverSession.setDefaultTimeZone(this.serverSession.getServerTimeZone());
}
追踪代码可知,当 MySQL 的 time_zone 值为 SYSTEM 时,会取 system_time_zone 值作为协调时区。
重点在这里!若 String configuredTimeZoneOnServer 得到的是 CST 那么 Java 会误以为这是 CST -0500 ,因此 TimeZone.getTimeZone(canonicalTimezone) 会给出错误的时区信息。
本机默认时区是 Asia/Shanghai +0800
,误认为服务器时区为 CST -0500
,实际上服务器是 CST +0800
。
Timestamp 被转换为会话时区的时间字符串了。问题到此已然明晰:
JDBC 误认为会话时区在 CST-5
JBDC 把 Timestamp+0 转为 CST-5 的 String-5
MySQL 认为会话时区在 CST+8,将 String-5 转为 Timestamp-13
最终结果相差 13 个小时!如果处在冬令时还会相差 14 个小时。
之前用的mysql是5.1.47,一直稳定运行。
某一天升级8.0版本之后,发现数据库datetime类型的字段数据异常。。。 与系统时间相差13小时。