欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java與MySQL導(dǎo)致的時間不一致問題分析

 更新時間:2024年07月03日 09:06:30   作者:碼畜c  
在使用MySQL的過程中,你可能會遇到時區(qū)相關(guān)問題,本文主要介紹了Java與MySQL導(dǎo)致的時間不一致問題分析,具有一定的參考價值,感興趣的可以了解一下

時間戳與時區(qū)的關(guān)系

時間戳一般指的是Unix 時間戳:是從1970年1月1日(UTC/GMT的午夜)開始所經(jīng)過的秒數(shù),不考慮閏秒。

那么和時區(qū)又有什么關(guān)系呢?

public static void main(String[] args) throws ParseException {
    TimeZone bjTimeZone = TimeZone.getTimeZone("Asia/Shanghai");
    TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");
    
    // 時間戳在不同時區(qū)下的日期
    Date date = new Date(0L);
    System.out.println("時間戳 0 對應(yīng)的系統(tǒng)時間:" + date);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sdf.setTimeZone(bjTimeZone);
    System.out.println("時間戳 0 在東八時區(qū)下表達的時間:" + sdf.format(date));
    sdf.setTimeZone(utcTimeZone);
    System.out.println("時間戳 0 在UTC時區(qū)下表達的時間:" + sdf.format(date));
    
    // 日期在不同時區(qū)下的時間戳
    sdf.setTimeZone(bjTimeZone);
    System.out.println("2024-02-25 00:00:00 在東八時區(qū)下的時間戳:" + sdf.parse("2024-02-25 00:00:00").getTime());
    sdf.setTimeZone(utcTimeZone);
    System.out.println("2024-02-25 00:00:00 在UTC時區(qū)下的時間戳:" + sdf.parse("2024-02-25 00:00:00").getTime());
}

時間戳 0 對應(yīng)的系統(tǒng)時間:Thu Jan 01 08:00:00 CST 1970
時間戳 0 在東八時區(qū)下表達的時間:1970-01-01 08:00:00
時間戳 0 在UTC時區(qū)下表達的時間:1970-01-01 00:00:00
2024-02-25 00:00:00 在東八時區(qū)下的時間戳:1708790400
2024-02-25 00:00:00 在UTC時區(qū)下的時間戳:1708819200

  • 一個時間戳在不同時區(qū)下所表達的時間是不一樣的。
  • 一個日期在不同時區(qū)下的時間戳是不同的。東八時區(qū)(北京時間)與 UTC 世界協(xié)調(diào)時間相差了八小時。可以通過時間戳的差值進行計算驗證:(1708819200 - 1708790400) / 60 / 60 = 8
  • 一個日期在不同時區(qū)下的時間戳的差值:時區(qū)間的偏移量
  • 兩個時區(qū)不同,但時間相同的日期表達的意義也不一樣,就如北京八點與美國八點的區(qū)別

查詢、修改 Java 程序使用的時區(qū)

public static void main(String[] args) {
 	// 查看默認時區(qū)與時區(qū)ID
 	TimeZone defaultTimeZone = TimeZone.getDefault();
    ZoneId systemDefaultZoneId = ZoneId.systemDefault();
	// sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null]
    System.out.println(defaultTimeZone);
    // Asia/Shanghai
    System.out.println(systemDefaultZoneId);
    
    // 設(shè)置默認時區(qū)
    TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("UTC")));
    // sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
    System.out.println(TimeZone.getDefault());
}

查詢、修改 MySQL 數(shù)據(jù)庫使用的時區(qū)

查詢:

show global variables like "%time_zone%";
Variable_nameValue
system_time_zone(系統(tǒng)時區(qū))UTC
time_zone(會話時區(qū))SYSTEM

系統(tǒng)時區(qū):UTC,即比東八時區(qū)慢8個小時。可以通過 SELECT NOW() 查詢當前時間對比 PC 上的時間驗證:MYSQL: 2024-02-24 19:07:31 / PC: 2024-02-25 03:07:31。該值讀取的就是 MySQL 服務(wù)所在的操作系統(tǒng)上使用的時區(qū),以 Linux 系統(tǒng)為例,可通過 date -R 查看:Sat, 24 Feb 2024 19:31:56 +0000。

會話時區(qū):采用系統(tǒng)時區(qū),即 UTC。

修改:系統(tǒng)時區(qū):修改系統(tǒng)時區(qū),即修改 MySQL 服務(wù)所在服務(wù)器的時區(qū),以 Linux 操作系統(tǒng)為例:cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime,將時區(qū)文件 copy 到 etc 目錄下且命名為 localtime。

會話時區(qū):

  • SQL 的方式:set global time_zone = '+8:00' or set global time_zone = 'Asia/Shanghai'
  • 修改 my.cnf 配置文件中的 default-time-zone=Asia/Shanghai 屬性

JDBC 讀取并設(shè)置 MySQL 服務(wù)使用的時區(qū)的流程

mysql-connector-j-8.0.33.jar 為例:

com.mysql.cj.protocol.a.NativeProtocol.configureTimeZone 設(shè)置MySQL服務(wù)使用的時區(qū)的流程:

  • 優(yōu)先讀取connectionTimeZoneserverTimezone jdbc 屬性作為會話使用的時區(qū)
  • 若配置的屬性為SERVER,則在第一次調(diào)用 ServerSession.getSessionTimeZone() 時讀取數(shù)據(jù)庫中配置的時區(qū)
  • 若沒有配置則以本地服務(wù)器的時區(qū)作為 MySQL 服務(wù)器的時區(qū)

NativeProtocol.configureTimeZone

JDBC 如何應(yīng)用的時區(qū)

說明:當前Java 程序東八時區(qū),MySQL服務(wù) UTC 時區(qū)。

存儲日期數(shù)據(jù)時,com.mysql.cj.protocol.a.SqlTimestampValueEncoder.getString 對于 Date 類型字段值的處理:將Java程序時區(qū)下的日期的時間戳,轉(zhuǎn)為MySQL服務(wù)時區(qū)下的日期(2024-02-25 11:52:56 > 2024-02-25 03:52:56

com.mysql.cj.protocol.a.SqlTimestampValueEncoder.getString

查詢?nèi)掌跀?shù)據(jù)時,com.mysql.cj.result.SqlTimestampValueFactory.localCreateFromDatetime 對于 Date 類型字段的處理:將MySQL服務(wù)時區(qū)下的日期的時間戳,轉(zhuǎn)為Java程序時區(qū)下的日期。(2024-02-24 21:34:55 > 2024-02-25 05:34:55

com.mysql.cj.result.SqlTimestampValueFactory.localCreateFromDatetime

根據(jù)源代碼的實現(xiàn)可以發(fā)現(xiàn)一個規(guī)律:都是先將日期根據(jù)所屬時區(qū)轉(zhuǎn)換為時間戳后,在根據(jù)需要轉(zhuǎn)換的時區(qū)轉(zhuǎn)換為最終日期。

Java 程序時區(qū)與 MySQL 服務(wù)使用時區(qū)不一致導(dǎo)致的問題

在 JDBC 讀取并設(shè)置 MySQL 服務(wù)使用的時區(qū)的流程 中說到:MySQL 服務(wù)使用的時區(qū)會受到 jdbc 參數(shù)的影響,也就是說可能會出現(xiàn):實際的數(shù)據(jù)庫時區(qū)與 jdbc 參數(shù)聲明的時區(qū)是不一樣的。最壞情況下會出現(xiàn):Java 程序時區(qū)、jdbc 聲明時區(qū)、實際數(shù)據(jù)庫時區(qū)都是不同的。

不對每種情況的流程進行逐個分析。一般開發(fā)時遇到時間不一致時,大概都是分為以下的兩種情況:

Java 程序時區(qū) 與 jdbc 參數(shù)時區(qū)一致,實際數(shù)據(jù)庫時區(qū)不一致:這種情況下,會出現(xiàn)程序、數(shù)據(jù)庫中展示日期都是相同的,但兩個日期分別對應(yīng)的時間戳不相同??雌饋硎菦]有問題,但實際上,數(shù)據(jù)庫中存儲的日期的時間戳已經(jīng)不是Java程序中該日期所對應(yīng)的時間戳了。如最開始說到的:一個日期在不同時區(qū)下的時間戳是不同的,那么表達的意義也不一樣,就如北京八點與美國八點的區(qū)別。整理一下 JDBC 驅(qū)動包在這種情況下的處理流程:

1)存儲:

2)讀取(能夠在轉(zhuǎn)為 Java 程序中的正確日期):

  • 獲取日期在 Java 程序時區(qū)下的時間戳
  • 根據(jù) JDBC 參數(shù)時區(qū)將時間戳轉(zhuǎn)為 MySQL 服務(wù)時區(qū)下的日期字符串(由于二者一致,所以結(jié)果沒有變化)
  • 組裝為數(shù)據(jù)包發(fā)送給實際的 MySQL 服務(wù)
  • MySQL 服務(wù)根據(jù)該日期字符串,轉(zhuǎn)為實際數(shù)據(jù)庫時區(qū)下的該日期(此時時間戳已經(jīng)不同了)
  • 讀取實際數(shù)據(jù)庫中的日期字符串
  • 根據(jù) JDBC 參數(shù)時區(qū)將日期轉(zhuǎn)為對應(yīng)時間戳
  • 將時間戳在根據(jù) Java 程序時區(qū)轉(zhuǎn)為對應(yīng)的日期(由于與 JDBC 參數(shù)時區(qū)一致,最終程序中的日期還是相同的)

Java 程序時區(qū) 與 實際數(shù)據(jù)庫時區(qū)不一致:這種情況下不考慮 jdbc 參數(shù)時區(qū)的影響,會出現(xiàn)程序、數(shù)據(jù)庫中展示的日期不同,但兩個不同日期的時間戳是一致的。捋一下 JDBC 處理流程:

1)存儲:

  • 獲取日期在 Java 程序時區(qū)下的時間戳
  • 獲取實際 MySQL 服務(wù)的時區(qū),并轉(zhuǎn)為該時區(qū)下的日期字符串(由于二者不一致,所以轉(zhuǎn)換結(jié)果日期也不同)
  • 組裝為數(shù)據(jù)包發(fā)送給實際的 MySQL 服務(wù)
  • MySQL 服務(wù)根據(jù)該日期字符串,轉(zhuǎn)為實際數(shù)據(jù)庫時區(qū)下的該日期(此時展示的日期已經(jīng)不同,但時間戳還是相同的)

2)讀?。軌蛟谵D(zhuǎn)為 Java 程序中的正確日期):

  • 讀取實際數(shù)據(jù)庫中的日期字符串
  • 獲取實際 MySQL 服務(wù)的時區(qū),將日期轉(zhuǎn)為對應(yīng)時間戳
  • 將時間戳在根據(jù) Java 程序時區(qū)轉(zhuǎn)為對應(yīng)的日期(雖然時區(qū)不同,但是時間戳還是同一個,能夠在正確轉(zhuǎn)為 Java 程序中的正確日期)

僅依靠數(shù)據(jù)庫時區(qū)生成時間數(shù)據(jù)(這是一種特殊情況):
當我們在為創(chuàng)建、修改時間字段添加了以下自動獲取時間屬性時:

`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間'

1)存儲:僅依賴數(shù)據(jù)庫時區(qū),不涉及時區(qū)轉(zhuǎn)換的問題
2)讀取(能夠在轉(zhuǎn)為 Java 程序中的正確日期):

  • 讀取實際數(shù)據(jù)庫中的日期字符串
  • 獲取實際 MySQL 服務(wù)的時區(qū),將日期轉(zhuǎn)為對應(yīng)時間戳
  • 將時間戳在根據(jù) Java 程序時區(qū)轉(zhuǎn)為對應(yīng)的日期(雖然時區(qū)不同,但是時間戳沒有發(fā)生變化,能夠在正確轉(zhuǎn)為 Java 程序中的正確日期)

解決方式

  • 將 Java 程序時區(qū)、jdbc 聲明的參數(shù)時區(qū)、實際數(shù)據(jù)庫時區(qū)設(shè)置為相同的時區(qū)
  • 將 Java 程序時區(qū)、實際數(shù)據(jù)庫時區(qū)設(shè)置為相同的時區(qū),且不設(shè)置 jdbc 聲明的參數(shù)時區(qū)這一干擾配置

到此這篇關(guān)于Java與MySQL導(dǎo)致的時間不一致問題分析的文章就介紹到這了,更多相關(guān)Java MySQL時區(qū)不一致 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 詳細聊一聊java中封裝的那點事

    詳細聊一聊java中封裝的那點事

    封裝是一個非常廣泛的概念,小到一個屬性的封裝,大到一個框架或者一個項目的封裝,下面這篇文章主要給大家介紹了關(guān)于java中封裝的那點事,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-04-04
  • SpringBoot 整合Tess4J庫實現(xiàn)圖片文字識別案例詳解

    SpringBoot 整合Tess4J庫實現(xiàn)圖片文字識別案例詳解

    Tess4J是一個基于Tesseract OCR引擎的Java接口,可以用來識別圖像中的文本,說白了,就是封裝了它的API,讓Java可以直接調(diào)用,今天給大家分享一個SpringBoot整合Tess4j庫實現(xiàn)圖片文字識別的小案例
    2023-10-10
  • Java隱藏特性之雙括號初始化詳解

    Java隱藏特性之雙括號初始化詳解

    Java?語言擁有許多隱藏而強大的特性,其中之一是雙括號初始化,這篇文章將詳細介紹雙括號初始化的概念、用法和示例代碼,希望對大家有所幫助
    2023-12-12
  • 簡單聊一聊Spring中Bean別名的處理原理

    簡單聊一聊Spring中Bean別名的處理原理

    今天來和小伙伴們聊一聊 Spring 中關(guān)于 Bean 別名的處理邏輯,別名,顧名思義就是給一個 Bean 去兩個甚至多個名字,整體上來說,在 Spring 中,有兩種不同的別名定義方式,感興趣的小伙伴跟著小編一起來看看吧
    2023-09-09
  • 解決對接JAVA SM2加密遇到的坑

    解決對接JAVA SM2加密遇到的坑

    這篇文章主要介紹了解決對接JAVA SM2加密遇到的坑,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Dubbo異步調(diào)用的實現(xiàn)介紹

    Dubbo異步調(diào)用的實現(xiàn)介紹

    dubbo默認使用同步的方式調(diào)用。但在有些特殊的場景下,我們可能希望異步調(diào)用dubbo接口,從而避免不必要的等待時間,這時候我們就需要用到異步。那么dubbo的異步是如何實現(xiàn)的呢?下面就來看看這個問題
    2022-09-09
  • SpringMVC 參數(shù)綁定之視圖傳參到控制器的實現(xiàn)代碼

    SpringMVC 參數(shù)綁定之視圖傳參到控制器的實現(xiàn)代碼

    這篇文章主要介紹了SpringMVC 參數(shù)綁定之視圖傳參到控制器的相關(guān)知識,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • 常用的Java數(shù)據(jù)結(jié)構(gòu)知識點匯總

    常用的Java數(shù)據(jù)結(jié)構(gòu)知識點匯總

    這篇文章主要介紹了常用的Java數(shù)據(jù)結(jié)構(gòu)知識點匯總,數(shù)據(jù)結(jié)構(gòu)分線性數(shù)據(jù)結(jié)構(gòu)和非線性數(shù)據(jù)結(jié)構(gòu),下面對此作詳細介紹,需要的小伙伴可以參考一下,希望對你的學習或工作有所幫助
    2022-03-03
  • Spring CGLlB動態(tài)代理實現(xiàn)過程解析

    Spring CGLlB動態(tài)代理實現(xiàn)過程解析

    這篇文章主要介紹了Spring CGLlB動態(tài)代理實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Jmerte分布式壓測及分布式壓測配置教程

    Jmerte分布式壓測及分布式壓測配置教程

    這篇文章主要介紹了Jmerte分布式壓測及分布式壓測配置,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04

最新評論