聊聊當業務資料時間和預期的不一樣,可以從哪些方向排查

liuxuhui發表於2021-09-09

前言

前些天業務部門的開發同事遇到了一個奇怪的bug,首先他們有個業務已經入庫的建立時間和伺服器時間相差了8個小時,其次當這個時間顯示到前端後,這個時間竟然和服務時間相差了好幾個月。

今天就這個問題,來做個覆盤,來聊聊當業務資料時間和預期的不一樣,可以從哪些方向排查

排查方向

1、資料庫和伺服器的時間不一致

1、檢視jdbc連結配置的時區,即serverTimezone的引數配置

注: 本文的時區都以東八區為基準,且資料庫為mysql

示例:

jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC

如上圖配置的時區是UTC,這樣就和東八區相差8個小時。如果按這種配法,當我們在程式碼層採用new Date()的方式,則落到資料庫的時間會比我們預期的時間相差8個小時。此時我們可以把jdbc上配置的時區引數改成

serverTimezone=Asia/Shanghai

2、檢視資料庫預設的時區配置

show variables like '%time_zone%';

圖片描述
由圖可以看出,此時資料庫時區預設配置不是東八區。我們可以透過如下方法進行修改

  • a、透過命令
##修改mysql全域性時區為東八區
set global time_zone = '+8:00'; 
 ##修改當前會話時區
set time_zone = '+8:00';

注: 透過命令列,無需重啟mysql服務,但當mysql服務再次被重啟,則上面的配置就會消失

  • b、透過配置檔案

linux系統則編輯my.cnf ,填入如下內容

[mysqld]
// 設定預設時區
default-time_zone='+8:00'

window的系統則編輯my.ini,填入的內容和linux一樣

注: 修改完配置後,需要重啟mysql服務

業務部門的建立時間相差8個小時,就是因為他們業務的建立時間統一是透過資料庫配置預設時間,當時他們資料庫預設時區是UTC,因此相差了8個小時。後來透過調整資料庫時區解決這個問題

2、容器和伺服器的時間不一致

1、進入容器內部檢視時間

docker exec -it 【容器ID或者NAME】 bin/bash -c date

2、如果是容器是已經生成

可以直接把宿主機的localtime複製到docker容器中,前提是宿主機的時間也是對的。命令如下

docker cp /etc/localtime 【容器ID或者NAME】:/etc/localtime

或者直接修改docker容器的時間也可以。進入容器內容,執行date -s

3、容器生成前,直接透過dockerfile配置【推薦】

FROM adoptopenjdk/openjdk8
VOLUME /tmp
#ENV JAVA_OPTS="-Dcom.sun.management.jmxremote.port=39083 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
ENV JAVA_OPTS=""
COPY localtime /etc/localtime
RUN echo "Asia/Shanghai" > /etc/timezone
COPY demo-biz/target/demo-service-biz-*.jar app.jar
ENTRYPOINT [ "sh", "-c", "exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

注: 因業務的dockerfile是統一根據模板生成,因此就沒這個問題

3、時間格式配置不正確

業務部門為了統一處理時間格式,在程式碼中做了如下配置

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(ListHttpMessageConverter?>> converters) {
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        //格式化json資料格式
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        //序列化時避免精度丟失,轉換為字串
        SerializeConfig serializeConfig = SerializeConfig.globalInstance;
        serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
        serializeConfig.put(Long.class, ToStringSerializer.instance);
        serializeConfig.put(Long.TYPE, ToStringSerializer.instance);

        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue);
        fastJsonConfig.setSerializeConfig(serializeConfig);
        fastJsonConfig.setDateFormat("yyyy-HH-dd HH:mm:ss");
        fastConverter.setFastJsonConfig(fastJsonConfig);

        ListMediaType> fastMediaTypes = new ArrayList>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        fastConverter.setSupportedMediaTypes(fastMediaTypes);

        converters.add(0,fastConverter);
    }


}

眼尖的朋友,可能發現了那個時間格式,長得和正常的格式是不一樣的。誰能想到,那個奇葩的bug,竟然是因為不小心把時間格式寫錯了。解決的方法就很簡單了,

fastJsonConfig.setDateFormat("yyyy-HH-dd HH:mm:ss");

改成

fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");

總結

上面就介紹幾種排查方向,尤其是最後一種,因為時間格式寫錯,導致時間顯示錯誤

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/756/viewspace-2797152/,如需轉載,請註明出處,否則將追究法律責任。

相關文章