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
备注
当
Mysq
l 返回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
此篇文章的评论功能已经停用。