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

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

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

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

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

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

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

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

  • 一個(gè)時(shí)間戳在不同時(shí)區(qū)下所表達(dá)的時(shí)間是不一樣的。
  • 一個(gè)日期在不同時(shí)區(qū)下的時(shí)間戳是不同的。東八時(shí)區(qū)(北京時(shí)間)與 UTC 世界協(xié)調(diào)時(shí)間相差了八小時(shí)??梢酝ㄟ^時(shí)間戳的差值進(jìn)行計(jì)算驗(yàn)證:(1708819200 - 1708790400) / 60 / 60 = 8
  • 一個(gè)日期在不同時(shí)區(qū)下的時(shí)間戳的差值:時(shí)區(qū)間的偏移量
  • 兩個(gè)時(shí)區(qū)不同,但時(shí)間相同的日期表達(dá)的意義也不一樣,就如北京八點(diǎn)與美國(guó)八點(diǎn)的區(qū)別

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

public static void main(String[] args) {
 	// 查看默認(rèn)時(shí)區(qū)與時(shí)區(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è)置默認(rèn)時(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ù)庫使用的時(shí)區(qū)

查詢:

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

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

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

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

會(huì)話時(shí)區(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ù)使用的時(shí)區(qū)的流程

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

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

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

NativeProtocol.configureTimeZone

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

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

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

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

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

com.mysql.cj.result.SqlTimestampValueFactory.localCreateFromDatetime

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

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

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

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

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

1)存儲(chǔ):

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

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

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

1)存儲(chǔ):

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

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

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

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

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

1)存儲(chǔ):僅依賴數(shù)據(jù)庫時(shí)區(qū),不涉及時(shí)區(qū)轉(zhuǎn)換的問題
2)讀?。軌蛟谵D(zhuǎn)為 Java 程序中的正確日期):

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

解決方式

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

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

相關(guān)文章

  • 詳細(xì)聊一聊java中封裝的那點(diǎn)事

    詳細(xì)聊一聊java中封裝的那點(diǎn)事

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

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

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

    Java隱藏特性之雙括號(hào)初始化詳解

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

    簡(jiǎn)單聊一聊Spring中Bean別名的處理原理

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

    解決對(duì)接JAVA SM2加密遇到的坑

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

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

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

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

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

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

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

    Spring CGLlB動(dòng)態(tài)代理實(shí)現(xiàn)過程解析

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

    Jmerte分布式壓測(cè)及分布式壓測(cè)配置教程

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

最新評(píng)論