SpringBoot2.x TimeZone问题

SpringBoot2.x TimeZone时区问题

Posted by Hyuga on June 14, 2019

问题描述

项目SpringBoot版本由1.5.13.RELEASE升级到2.1.3.RELEASE后,发现dao层插入和查出的时间相关字段,时间全都和数据库里存储的值对应不上,如下:

数据库存储的值:2019-06-13 15:22:03 

代码查询出来的值:2019-06-14 04:22:03

解决过程

更改数据库连接参数

basic.mysql.url=jdbc:mysql:replication://x.x.x.x,x.x.x.x/xx?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useLegacyDatetimeCode=false&serverTimezone=UTC

更改后,返回时间对比如下:

数据库存储的值:2019-06-13 15:22:03 

代码查询出来的值:2019-06-13 23:22:03

变成了典型的 +8 问题。。。


配置启动类参数

在启动类加上

@PostConstruct 
void setDefaultTimezone() {
    TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai")); 
}  
 
在启动类 启动run方法里加上

public static void main(String[] args) {    
    TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));    
    //TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));    
    //TimeZone.setDefault(TimeZone.getTimeZone("UTC")) 
    SpringApplication.run(BaseMicroServiceApplication.class, args); }

很可惜,无效!


在应用配置文件配置

application.ymlbootstrap.yml上配置

## json setting
spring:
  #spring boot2.0.0 架构问题 时间处理 (映射,时区问题)
  jackson:
    #参数意义:
    #JsonInclude.Include.ALWAYS        默认
    #JsonInclude.Include.NON_DEFAULT   属性为默认值不序列化
    #JsonInclude.Include.NON_EMPTY     属性为 空(””) 或者为 NULL 都不序列化
    #JsonInclude.Include.NON_NULL      属性为NULL   不序列化
    #default-property-inclusion: ALWAYS
    date-format: yyyy-MM-dd HH:mm:ss
    #time-zone: GMT+8
    time-zone: Asia/Shanghai
    serialization:
      write-dates-as-timestamps: false

很遗憾,无效!

最终方案

更改数据库连接参数

basic.mysql.url=jdbc:mysql:replication://x.x.x.x,x.x.x.x/xx?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useLegacyDatetimeCode=false&serverTimezone=GMT+8

顺利解决时间+8问题,插入查询时间正常!!!

问题产生原因

经过排查及查阅资料,出现这个问题并不是SpringBoot2.x的问题,而是mysql数据库链接jar包版本的问题。

由于升级了SpringBoot2.x,对应的mysql-connector-java版本从5.1.36升级到8.0.15.

版本升级后,查询出来的时间会比数据库存储的值多出6小时。

回想起最初发现这个问题的时候,时间差异是有14小时,如下:

数据库存储的值:2019-06-13 15:22:03 

代码查询出来的值:2019-06-14 04:22:03

差异 = 8 + 6 = 14小时

数据库连接参数改为serverTimezone=UTC后,时间变成了:

数据库存储的值:2019-06-13 15:22:03 

代码查询出来的值:2019-06-13 23:22:03

差异 = 8小时

最终数据库连接参数改为serverTimezone=GMT+8后,一切才恢复正常。


Ps:

其实最终就是要把数据库和程序的时区设置为一致,UTC也行,GMT+8也好,主要是保持一致。

以下举例将两者设置为UTC.

 
数据库连接参数: 
spring.datasource.url=jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf-8&useLegacyDatetimeCode=false&serverTimezone=UTC

其中useLegacyDatetimeCode参数默认是true,我们需要手动设置为false,否则无效。 

代码:
@SpringBootApplication
public class Application {
      @PostConstruct
      void started() {
            TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
            //TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
            //TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
      } 
      public static void main(String[] args) { 
            SpringApplication.run(Application.class, args); 
      } 
}

这个方案我没亲自尝试过,不过应该也是可以解决问题的。

参考资料