JDBC 链接 Mysql 提示:时区不识别
错误日志
c.m.c.e.InvalidConnectionAttributeException: The server time zone value 'PDT' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specific time zone value if you want to utilize time zone support.
原因
由于 Client 端连接字符串没有设置 serverTimezone=America/Los_Angeles 参数, 同时 Mysql 端也没有设置时区 time_zone, 此时 Mysql 采用 OS 操作系统 的 system_time_zone, 当这个值无法被 JDBC SDK 识别时,就会提示如上错误
详细分析
Mysql 时区
SHOW variables LIKE '%time_zone%';
SELECT @@global.time_zone, @@session.time_zone;
备注
SYSTEM代表 时区来自system_time_zone, 而system_time_zone来自OS 操作系统,启动Mysql时获取
@@global.time_zone代表Server全局时区
@@session.time_zone代表Client当前会话时区
如果 Mysql 没有设置 time_zone ,显示结果如下:
| Variable_name | Value |
|---|---|
| system_time_zone | PDT |
| time_zone | SYSTEM |
| @@global.time_zone | @@session.time_zone |
|---|---|
SYSTEM |
SYSTEM |
如果 Mysql 设置了 time_zone ,显示结果如下:
| Variable_name | Value |
|---|---|
| system_time_zone | PDT |
| time_zone | America/Los_Angeles |
| @@global.time_zone | @@session.time_zone |
|---|---|
America/Los_Angeles |
America/Los_Angeles |
JDBC SDK
SDK mysql-connector-java 版本 8.0.18
源码分析
mysql-connector-java-8.0.18.jar!\com\mysql\cj\protocol\a\NativeProtocol.class
备注
当
Mysql 返回time_zone==SYSTEM时,读取system_time_zone
如果
Client连接字符串没有配置serverTimezone或者 值为Null或者Empty; 验证system_time_zone是否符合预期
如果
Client连接字符串有配置serverTimezone,则验证serverTimezone是否符合预期

源码片段
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());
}
mysql-connector-java-8.0.18.jar!\com\mysql\cj\util\TimeUtil.class
备注
time_zone为+08:00或者-07:00; 直接返回GMT+time_zone
否则
time_zone必须存在于/com/mysql/cj/util/TimeZoneMapping.properties

源码片段
public static String getCanonicalTimezone(String timezoneStr, ExceptionInterceptor exceptionInterceptor) {
if (timezoneStr == null) {
return null;
} else {
timezoneStr = timezoneStr.trim();
if (timezoneStr.length() > 2 && (timezoneStr.charAt(0) == '+' || timezoneStr.charAt(0) == '-') && Character.isDigit(timezoneStr.charAt(1))) {
return "GMT" + timezoneStr;
} else {
Class var2 = TimeUtil.class;
synchronized(TimeUtil.class) {
if (timeZoneMappings == null) {
loadTimeZoneMappings(exceptionInterceptor);
}
}
String canonicalTz;
if ((canonicalTz = timeZoneMappings.getProperty(timezoneStr)) != null) {
return canonicalTz;
} else {
throw (InvalidConnectionAttributeException)ExceptionFactory.createException(InvalidConnectionAttributeException.class, Messages.getString("TimeUtil.UnrecognizedTimezoneId", new Object[]{timezoneStr}), exceptionInterceptor);
}
}
}
}
链接字符串
参考链接字符串参数
?serverTimezone=America/Los_Angeles&useUnicode=true&characterEncoding=utf8&useServerPrepStmts=true&autoReconnect=true&failOverReadOnly=false&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
参考文档
最后修改于 2024-03-12
此篇文章的评论功能已经停用。