聊聊當(dāng)業(yè)務(wù)數(shù)據(jù)時間和預(yù)期的不一樣,可以從哪些方向排查
前言
前些天業(yè)務(wù)部門的開發(fā)同事遇到了一個奇怪的bug,首先他們有個業(yè)務(wù)已經(jīng)入庫的創(chuàng)建時間和服務(wù)器時間相差了8個小時,其次當(dāng)這個時間顯示到前端后,這個時間竟然和服務(wù)時間相差了好幾個月。
今天就這個問題,來做個復(fù)盤,來聊聊當(dāng)業(yè)務(wù)數(shù)據(jù)時間和預(yù)期的不一樣,可以從哪些方向排查
排查方向
1、數(shù)據(jù)庫和服務(wù)器的時間不一致
1、查看jdbc鏈接配置的時區(qū),即serverTimezone的參數(shù)配置
注: 本文的時區(qū)都以東八區(qū)為基準(zhǔn),且數(shù)據(jù)庫為mysql
示例:
- jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
如上圖配置的時區(qū)是UTC,這樣就和東八區(qū)相差8個小時。如果按這種配法,當(dāng)我們在代碼層采用new Date()的方式,則落到數(shù)據(jù)庫的時間會比我們預(yù)期的時間相差8個小時。此時我們可以把jdbc上配置的時區(qū)參數(shù)改成
- serverTimezone=Asia/Shanghai
2、查看數(shù)據(jù)庫默認(rèn)的時區(qū)配置
- show variables like '%time_zone%';
由圖可以看出,此時數(shù)據(jù)庫時區(qū)默認(rèn)配置不是東八區(qū)。我們可以通過如下方法進(jìn)行修改
a、通過命令
- ##修改mysql全局時區(qū)為東八區(qū)
- set global time_zone = '+8:00';
- ##修改當(dāng)前會話時區(qū)
- set time_zone = '+8:00';
注: 通過命令行,無需重啟mysql服務(wù),但當(dāng)mysql服務(wù)再次被重啟,則上面的配置就會消失
b、通過配置文件
linux系統(tǒng)則編輯my.cnf ,填入如下內(nèi)容
- [mysqld]
- // 設(shè)置默認(rèn)時區(qū)
- default-time_zone='+8:00'
window的系統(tǒng)則編輯my.ini,填入的內(nèi)容和linux一樣
注: 修改完配置后,需要重啟mysql服務(wù)
業(yè)務(wù)部門的創(chuàng)建時間相差8個小時,就是因為他們業(yè)務(wù)的創(chuàng)建時間統(tǒng)一是通過數(shù)據(jù)庫配置默認(rèn)時間,當(dāng)時他們數(shù)據(jù)庫默認(rèn)時區(qū)是UTC,因此相差了8個小時。后來通過調(diào)整數(shù)據(jù)庫時區(qū)解決這個問題
2、容器和服務(wù)器的時間不一致
1、進(jìn)入容器內(nèi)部查看時間
- docker exec -it 【容器ID或者NAME】 bin/bash -c date
2、如果是容器是已經(jīng)生成
可以直接把宿主機的localtime拷貝到docker容器中,前提是宿主機的時間也是對的。命令如下
- docker cp /etc/localtime 【容器ID或者NAME】:/etc/localtime
或者直接修改docker容器的時間也可以。進(jìn)入容器內(nèi)容,執(zhí)行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" ]
注: 因業(yè)務(wù)的dockerfile是統(tǒng)一根據(jù)模板生成,因此就沒這個問題
3、時間格式配置不正確
業(yè)務(wù)部門為了統(tǒng)一處理時間格式,在代碼中做了如下配置
- @Configuration
- public class WebConfig implements WebMvcConfigurer {
- @Override
- public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
- FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
- //格式化json數(shù)據(jù)格式
- FastJsonConfig fastJsonConfig = new FastJsonConfig();
- //序列化時避免精度丟失,轉(zhuǎn)換為字符串
- 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);
- List<MediaType> fastMediaTypes = new ArrayList<>();
- fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
- fastMediaTypes.add(MediaType.APPLICATION_JSON);
- fastConverter.setSupportedMediaTypes(fastMediaTypes);
- converters.add(0,fastConverter);
- }
- }
眼尖的朋友,可能發(fā)現(xiàn)了那個時間格式,長得和正常的格式是不一樣的。誰能想到,那個奇葩的bug,竟然是因為不小心把時間格式寫錯了。解決的方法就很簡單了,
- fastJsonConfig.setDateFormat("yyyy-HH-dd HH:mm:ss");
改成
- fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
總結(jié)
上面就介紹幾種排查方向,尤其是最后一種,因為時間格式寫錯,導(dǎo)致時間顯示錯誤