文档章节

jdbc mysql connector 6 时区问题

purely
 purely
发布于 2017/07/21 17:20
字数 920
阅读 130
收藏 0

起因

之前因为mysql connector 5的某个版本有OOM的风险: 传送门

所以调整了timeout时间和升级了connector到6.

一切以为都是正常的,不过却出现了一场惊天动地的抢险修复😂。

苦难

事情出在第二天,刚好周六。运营反馈说线上所有的贷款借据日期都不准了,差了14个小时。

于事在家里干紧vpn连上后,查看情况。

不看不知道,一看吓一跳,还真的TM都差了14个小时。这不是要人命吗,别说数据对不上,关这一天的利息就不知道多少钱了,想想就可怕啊。

分析

此时最需要的时冷静。待人静下心来,以及和同事沟通排查。这个程序上线半年多没出现这个问题,那么肯定是最近的更新导致的。最近的更新就是改了timeout和升级了 jdbc mysql connector的版本。timeout应该不会有问题,那问题很可能在connector上。

于是在本地新建一个工程用新版connector连上mysql试了一下,果然差了14个小时。

解决

问题找到了,那就要解决啊。一开始还真不知道怎么解决,问题找到了,然没有查到根本原因啊。后面查了查万能的google,发现在jdbc的url里指定timezone为东8区就可以了,如下

serverTimezone=GMT%2b8:00

这里的%2b是url encode后的+,decode后就是serverTimezone=GMT+8:00

原理

既然知道怎么解决了,在解决完问题,修复数据后,必须要查清楚具体原因。后来仔细排查下来,要jdk的文档中找到了答案。

先来看一下mysql的时区设置:

show variables like '%time_zone%';
system_time_zone	CST
time_zone	SYSTEM

可以看出system_time_zone是CST,也就是东8区,time_zone用的是SYSTEM,那也就是system_time_zone的CST。

然后再看一下connector里怎么处理时区的,在ConnectionImpl类中,有一个

 private void initializePropsFromServer() throws SQLException

在里面可以看到初时化时区的方法

this.session.configureTimezone();

点进去查看

   public void configureTimezone() {
        String configuredTimeZoneOnServer = getServerVariable("time_zone");

        if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
            configuredTimeZoneOnServer = getServerVariable("system_time_zone");
        }

        String canonicalTimezone = getPropertySet().getStringReadableProperty(PropertyDefinitions.PNAME_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.serverTimezoneTZ = 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.serverTimezoneTZ.getID().equals("GMT")) {
                throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("Connection.9", new Object[] { canonicalTimezone }),
                        getExceptionInterceptor());
            }
        }

        this.defaultTimeZone = this.serverTimezoneTZ;
    }

这里的PropertyDefinitions.PNAME_serverTimezone就是jdbc url上的serverTimezone变量,

可以很清楚地看出优先使用serverTimezon变量,如果没有,则用mysql的time_zone。

在没有serverTimezone变量时,读取mysql的time_zone为SYSTEM, 则进一步读取system_time_zone,也就是CST。

然后用CST做为时区,那问题来了,CST不就是东8区吗,怎么会有问题?

查看jdk的TimeZone类,看到注释中有这个一句:

* For compatibility with JDK 1.1.x, some other three-letter time zone IDs
* (such as "PST", "CTT", "AST") are also supported. However, <strong>their
* use is deprecated</strong> because the same abbreviation is often used
* for multiple time zones (for example, "CST" could be U.S. "Central Standard
* Time" and "China Standard Time"), and the Java platform can then only
* recognize one of them.

看到坑了没?CST可以是美国的中央时区,也可以是中国标准时区。所以现在问题已经找到了。

  1. 在mysql中CST代表的是中国标准时区,东8区。
  2. 在jdk中,CST代表的是美国中央时区

所以这里就出现在时区错乱的现象。

在jdk中,CTT表示东8区,所以也可以用serverTimezone=CTT,不过最好用GMT+8:00

ps:jdk版本1.8

------

© 著作权归作者所有

共有 人打赏支持
purely

purely

粉丝 18
博文 19
码字总数 8155
作品 0
杭州
高级程序员
JDBC(java连接MySQL)

Java连接MySQL 今天下午自己在试着连接MySQL数据库,作为初学者,遇到了很多问题,自己也不是很清楚,就慢慢的查资料,看论坛慢慢的总结了一些经验,上来和大家分享一下!(有些专业名词记得...

段豆豆
2013/04/22
0
1
Mysql连接报错:Unknown system variable 'language'

一:问题描述:mysql测试连接一致报错:Unknown system variable 'language' 未知名的系统变量语言 二:用的Mysql的版本 5.6 用的连接 jar mysql-connector-java-5.1.36.jar 三:找到问题,m...

EDIAGD
2015/07/24
0
0
Multi-Host Connections(三)

ReplicationDriver 针对Master/Slave,Mysql jdbc drivrer : ReplicationDriver https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-master-slave-replication-connection.html http......

墨子Zhai
06/06
0
0
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorEx

一直用oracle,好久没有用mysql,今天搭建了一个mysql的web开发环境。竟然抛出这个异常: Unknown character set: 'utf8mb4' org.springframework.jdbc.CannotGetJdbcConnectionException: ...

alonelywolf
2014/12/20
0
0
JDBC连接MySQL数据库及示例

DBC是Sun公司制定的一个可以用Java语言连接数据库的技术。 一、JDBC基础知识 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提...

aminqiao
2014/06/10
0
1

没有更多内容

加载失败,请刷新页面

加载更多

GO冒泡,二分查找

package mainimport("fmt")func main() {var arr [5]int = [5]int{11,13,9,2,25}maopao(&arr)fmt.Println("arr = ", arr) //[2 9 11 13 25]findIndex := binaryFind(&arr, 0......

汤汤圆圆
14分钟前
1
0
工作2年半跳槽面试阿里,成功拿到offer,凭什么?

2015年刚毕业的我,进入了一家小小的公司实习工作,在学校学了三年软件开发的我,还是想去寻找一份互联网行业的工作,这样更能学以致用发挥自己的特长。一直到18年三月份,我辞掉已有的工作,...

java知识分子
19分钟前
1
0
讲述下:Linux的10个最危险的命令

导读 Linux命令行佷有用、很高效,也很有趣,但有时候也很危险,尤其是在你不确定你自己在正在做什么时候。这篇文章将会向你介绍十条命令,但你最好不要尝试着去使用。 当然,以下命令通常都...

问题终结者
23分钟前
1
0
分库分表后如何部署上线?

引言 我们先来讲一个段子 面试官:“有并发的经验没?” 应聘者:“有一点。” 面试官:“那你们为了处理并发,做了哪些优化?” 应聘者:“前后端分离啊,限流啊,分库分表啊。。” 面试官:...

Java烂猪皮
28分钟前
1
0
Redis源码阅读笔记-快速列表

快速列表 快速列表(quicklist)是由压缩列表(ziplist)组成的一个双向链表,链表中,每一个节点都是以压缩列表(ziplist)的结构保存。 在 Redis3.2 后加入的新数据结构,在列表键中取代了双向链...

Jian_Ming
46分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部