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

Java與MySQL時間不一致問題解決

 更新時間:2023年01月05日 10:37:48   作者:騎個小蝸牛  
本文主要介紹了Java與MySQL時間不一致問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、問題情況描述

有時會遇到這樣的問題:MySQL中datetime、timestamp類型的列,Java與MySQL時間不一致。

在Java的數(shù)據(jù)庫配置url參數(shù)后面加serverTimezone=GMT%2B8,問題就解決了,但具體是什么導(dǎo)致的這一問題呢?

其實,Java與MySQL時間不一致主要是因為:CST時區(qū)的混亂問題

二、CST時區(qū)混亂

1. CST有四種含義

CST是一個混亂的時區(qū),它有四種含義:

美國標(biāo)準(zhǔn)時間 Central Standard Time (USA):UTC-06:00(或UTC-05:00)

  • 夏令時:3月11日至11月7日,使用UTC-05:00
  • 冬令時:11月8日至次年3月11日,使用UTC-06:00

澳大利亞標(biāo)準(zhǔn)時間 Central Standard Time (Australia):UTC+09:30

中國標(biāo)準(zhǔn)時 China Standard Time:UTC+08:00

古巴標(biāo)準(zhǔn)時 Cuba Standard Time:UTC-04:00

CST在Linux、MySQL、Java中的含義:

  • 在Linux或MySQL中,CST表示的是:中國標(biāo)準(zhǔn)時間(UTC+08:00)
  • 在Java中,CST表示的是:中央標(biāo)準(zhǔn)時間(美國標(biāo)準(zhǔn)時間)(UTC-05:00或UTC-06:00)

Java中CST時區(qū)的分析:

public static void main(String[] args) {
    // 完整時區(qū)ID與時區(qū)描述:一共628個
    String[] ids = TimeZone.getAvailableIDs();
    for (String id : ids) {
        // System.out.println(id+"\t"+TimeZone.getTimeZone(id).getDisplayName());
    }
    // 系統(tǒng)默認(rèn)時區(qū)
    TimeZone defaultTimeZone = TimeZone.getDefault();
    System.out.println("系統(tǒng)默認(rèn)時區(qū):"+defaultTimeZone.getID()+"\t"+defaultTimeZone.getDisplayName());
    // 北京時區(qū)
    TimeZone bjTimeZone = TimeZone.getTimeZone("Asia/Shanghai");
    System.out.println("北京時區(qū):"+bjTimeZone.getID()+"\t"+bjTimeZone.getDisplayName());
    // 東京時區(qū)
    TimeZone djTimeZone = TimeZone.getTimeZone("Asia/Tokyo");
    System.out.println("東京時區(qū):"+djTimeZone.getID()+"\t"+djTimeZone.getDisplayName());
    // CST時區(qū)
    TimeZone cstTimeZone = ZoneInfo.getTimeZone("CST");
    System.out.println("CST時區(qū):"+cstTimeZone.getID()+"\t"+cstTimeZone.getDisplayName());

    Date date = new Date(0L);
    System.out.println("時間戳=0對應(yīng)系統(tǒng)時間:"+date.toString());
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sdf.setTimeZone(bjTimeZone);// 設(shè)置北京時區(qū)
    System.out.println("時間戳0對應(yīng)北京時間:" + sdf.format(date));
    sdf.setTimeZone(djTimeZone);// 設(shè)置東京時區(qū)
    System.out.println("時間戳0對應(yīng)東京時間:" + sdf.format(date));
    sdf.setTimeZone(cstTimeZone);// 設(shè)置CST時區(qū)
    System.out.println("時間戳0對應(yīng)CST時間:" + sdf.format(date));
}

控制臺輸出:

系統(tǒng)默認(rèn)時區(qū):Asia/Shanghai    中國標(biāo)準(zhǔn)時間
北京時區(qū):Asia/Shanghai    中國標(biāo)準(zhǔn)時間
東京時區(qū):Asia/Tokyo    日本標(biāo)準(zhǔn)時間
CST時區(qū):CST    中央標(biāo)準(zhǔn)時間
時間戳=0對應(yīng)系統(tǒng)時間:Thu Jan 01 08:00:00 CST 1970
時間戳0對應(yīng)北京時間:1970-01-01 08:00:00
時間戳0對應(yīng)東京時間:1970-01-01 09:00:00
時間戳0對應(yīng)CST時間:1969-12-31 18:00:00

由輸出可知:

CST在Java中(TimeZone中的CST)表示的是中央標(biāo)準(zhǔn)時間(美國標(biāo)準(zhǔn)時間)

但需注意:Date中的CST是表示的中國標(biāo)準(zhǔn)時間

時間戳永遠(yuǎn)指的是UTC/GMT的值,同一時間戳在不同時區(qū)表示不同的絕對時間

中國的時區(qū)ID為Asia/Shanghai。

2. 什么是時區(qū)

為了照顧到各地區(qū)的使用方便,又使其他地方的人容易將本地的時間換算到別的地方時間上去。有關(guān)國際會議決定將地球表面按經(jīng)線從南到北,劃成24個區(qū)域,并且規(guī)定相鄰區(qū)域的時間相差1小時。

但由于國家常常是跨越多個時區(qū)的,為了照顧到行政上的方便,所以通常國家都會定義一個統(tǒng)一標(biāo)準(zhǔn)際的時區(qū)來使用,如中國就是統(tǒng)一使用東八區(qū)時間標(biāo)準(zhǔn)(北京時間)。

因為時區(qū)眾多,所以需要一個標(biāo)準(zhǔn)時間作為基準(zhǔn):

  • 早期基準(zhǔn)是:GMT(格林尼治標(biāo)準(zhǔn)時間)
  • 后來基準(zhǔn)是:UTC(協(xié)調(diào)世界時)

由于地球在它的橢圓軌道里的運(yùn)動速度不均勻,這個時刻可能和實際的太陽時相差16分鐘,地球每天的自轉(zhuǎn)是有些不規(guī)則的,而且正在緩慢減速。所以,GMT(格林尼治標(biāo)準(zhǔn)時間)已經(jīng)不再適合被作為標(biāo)準(zhǔn)時間使用。而是UTC(協(xié)調(diào)世界時)是原子時秒長為基礎(chǔ),更合適。UTC在時刻上盡量接近于GMT,這兩者幾乎是一樣的。

UTC這套時間系統(tǒng)被應(yīng)用于許多互聯(lián)網(wǎng)和萬維網(wǎng)的標(biāo)準(zhǔn)中,例如,網(wǎng)絡(luò)時間協(xié)議就是協(xié)調(diào)世界時在互聯(lián)網(wǎng)中使用的一種方式。

  • 如果本地時間比UTC時間快,例如中國大陸的時間比UTC快8小時,寫作UTC+8(東8區(qū))。
  • 如果本地時間比UTC時間慢,例如夏威夷的時間比UTC時間慢10小時,寫作UTC-10(西10區(qū))。

三、絕對時間與本地時間

絕對時間與本地時間關(guān)系:絕對時間 = 本地時間 & 時區(qū)偏移量 (AbsoluteTime = LocalDateTime & Offset)

1. 絕對時間

絕對時間(AbsoluteTime)是一個指向絕對時間線上的一個確定的時刻,不受所在地的影響。

UTC時間就是一個絕對時間。

當(dāng)我們記錄一個時間為1970-01-01T00:00:00Z(UTC描述時間的標(biāo)準(zhǔn)格式)時,這個時間的定義是沒有任何歧義的,在地球上的任何地方,他們的UTC時間也一定是相同的。

Unix時間戳也是一個絕對時間。

Unix時間戳的定義與時區(qū)無關(guān)。時間戳是指從絕對時間點(UTC時間1970年1月1日午夜)起經(jīng)過的秒數(shù)(或毫秒)。無論您使用什么時區(qū),時間戳都代表一個時刻,在任何地方都是相同的。

2. 本地時間

本地時間(LocalDateTime)是某一時區(qū)的時間。

舉例:北京時間2022-10-10 08:00:00。

  • “2022-10-10 08:00:00”是本地時間(不含時區(qū)描述)
  • “北京時間2022-10-10 08:00:00”整體是絕對時間(含時區(qū)描述)

3. 時區(qū)偏移量

全球分為24個時區(qū),每個時區(qū)和零時區(qū)相差了數(shù)個小時,也就是這里所說的時區(qū)偏移量(Offset)。

例如:北京時間2022-10-10 08:00:00,它本身是一個絕對時間,表示成UTC時間是2020-08-24T03:00:00+08:00

  • 其中的2020-08-24T03:00:00是本地時間
  • 其中的+08:00可以看作是時區(qū)偏移量

時區(qū)偏移量 = 地區(qū) & 規(guī)則 (Offset = Zone & Rules)

這里的規(guī)則(Rules)可能是一個變化的值,如果我們單純地認(rèn)為中國的時區(qū)偏移量是8個小時,就出錯了。

舉例說明:

中國其實也實行過夏令時,(1992年之后中國已經(jīng)沒有再實行過夏令時了,所以大家對這個概念并不熟悉)。

  • 當(dāng)實行夏令時,中國標(biāo)準(zhǔn)時間的時區(qū)偏移量就是+09:00
  • 當(dāng)非夏令時,中國標(biāo)準(zhǔn)時間的時區(qū)偏移量就是+08:00

因此,一個地區(qū)的時區(qū)偏移量是多少,是由當(dāng)?shù)氐恼邲Q定的,可能會隨著季節(jié)而發(fā)生變化,這就是上面所說的規(guī)則。

四、MySQL服務(wù)端時區(qū)

MySQL時區(qū)相關(guān)參數(shù)有兩個:

  • system_time_zone(系統(tǒng)時區(qū))
  • time_zone(全局時區(qū)或當(dāng)前會話時區(qū))

1. system_time_zone(系統(tǒng)時區(qū))

在MySQL啟動時會檢查當(dāng)前系統(tǒng)的時區(qū)并根據(jù)系統(tǒng)時區(qū)設(shè)置全局參數(shù)system_time_zone的值。值可以為UTC、CST、WIB等,默認(rèn)值一般為CST,該值是只讀的。

2. time_zone(全局時區(qū)或當(dāng)前會話時區(qū))

全局時區(qū):mysql服務(wù)端使用的時區(qū),可以修改,默認(rèn)值SYSTEM

mysql> show global variables like "%time_zone%";
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec)

mysql> set global time_zone = '+9:00';
Query OK, 0 rows affected (0.00 sec)

mysql> show global variables like "%time_zone%";
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | +09:00 |
+------------------+--------+
2 rows in set (0.00 sec)

此時查到的time_zone為全局時區(qū)

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

該命令使全局時區(qū)的修改立即生效,否則只有等mysql服務(wù)重啟才會生效。

會話時區(qū):當(dāng)前會話的時區(qū),默認(rèn)取全局時區(qū)的值,可以修改

mysql> show variables like "%time_zone%";
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec)

mysql> set time_zone = '+9:00';
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like "%time_zone%";
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | +09:00 |
+------------------+--------+
2 rows in set (0.00 sec)

此時查到的time_zone為當(dāng)前會話時區(qū)

五、問題具體分析

本文使用的MySQL驅(qū)動為cj驅(qū)動。

Java通過MySQL的jdbc驅(qū)動連接MySQL服務(wù)端:

  • 通過jdbc的serverTimezone參數(shù)設(shè)置數(shù)據(jù)庫連接的時區(qū)。
  • 當(dāng)未設(shè)置serverTimezone時,數(shù)據(jù)庫將連接使用MySQL服務(wù)端的time_zone(全局時區(qū)),默認(rèn)值為CST。time_zone的默認(rèn)值為SYSTEM,而SYSTEM取的是system_time_zone(系統(tǒng)時區(qū))的值,system_time_zone的默認(rèn)值就是CST。

對于CST,文章上文有提過:

  • MySQL中,CST表示的是:中國標(biāo)準(zhǔn)時間(UTC+08:00)
  • Java中,CST表示的是:美國標(biāo)準(zhǔn)時間(UTC-05:00或UTC-06:00)

由于Java和MySQL服務(wù)端對CST時區(qū)的不同解讀,最終導(dǎo)致了Java與MySQL時間不一致的問題。

關(guān)于serverTimezone

分析mysql的jdbc驅(qū)動代碼。MySQL驅(qū)動創(chuàng)建數(shù)據(jù)庫連接后,會配置此連接的時區(qū):

  • 普通驅(qū)動:使用com.mysql.jdbc.ConnectionImpl#configureTimezone()配置連接的時區(qū)
  • cj驅(qū)動:使用com.mysql.cj.protocol.a.NativeProtocol#configureTimezone()配置連接的時區(qū)

數(shù)據(jù)庫連接時區(qū)的設(shè)置:

  • 如果配置了serverTimezone,則會使用serverTimezone配置的時區(qū)
  • 如果沒配置,會去取數(shù)據(jù)庫中time_zone變量所配置的時區(qū)

serverTimezone配置的注意事項:

  • 如果未配置serverTimezone,且數(shù)據(jù)庫time_zone是CST,時間會不一致
  • 如果未配置serverTimezone,但數(shù)據(jù)庫time_zone不是CST(如GMT),時間一致
  • 如果配置了serverTimezone,但與數(shù)據(jù)庫time_zone不是同一時區(qū),時間會不一致
  • 如果配置了serverTimezone,且與數(shù)據(jù)庫time_zone是同一時區(qū),時間一致

你或許會發(fā)現(xiàn)一個奇怪的事情:貌似我配置的serverTimezone與據(jù)庫time_zone不是同一時區(qū)。但是Java中的存入時間和查詢得到的時間明明是一致且正確的,好像和上面描述得不一樣呀。

這里需要強(qiáng)調(diào)一下,上面所說的時間不一致是指的Java中的時間與MySQL數(shù)據(jù)庫中的時間(并不是Java中的存入時間和查詢得到的時間)。

為何Java中的存入時間和查詢得到的時間是一致且正確的?

舉個例子說明:

serverTimezone=+9(東九區(qū)),time_zone=+8:00(東八區(qū)),此時準(zhǔn)備把Java中的時間"2022-10-15 08:00:00"存入數(shù)據(jù)庫

  • Java存入到MySQL時,誤認(rèn)為MySQL數(shù)據(jù)庫的時區(qū)是東九區(qū),時間+1小時,MySQL最終得到時間為:2022-10-15 09:00:00
  • MySQL返回給Java時,誤認(rèn)為MySQL返回的時間是東九區(qū)的時間,時間-1小時,Java最終得到的時間為:2022-10-15 08:00:00,和正確時間一致

Java到MySQL的過程,以及MySQL到Java的過程,時間的處理在MySQL JDBC驅(qū)動環(huán)節(jié)。

serverTimezone配置的歸納總結(jié):

  • 如果數(shù)據(jù)庫time_zone是CST,請配置serverTimezone=%2B8(+08:00)
  • 如果數(shù)據(jù)庫time_zone是GMT(或其它MySQL與Java解析結(jié)果一致的時區(qū)格式),可以不配置serverTimezone參數(shù)。但如果要配置,請配置與數(shù)據(jù)庫數(shù)據(jù)庫time_zone一致的時區(qū)

雖然配置的serverTimezone與數(shù)據(jù)庫數(shù)據(jù)庫time_zone時區(qū)不一致,Java寫入后查詢得到的時間也是正常的,但MySQL中存的時間已經(jīng)是錯誤的了。

時間戳與時區(qū)無關(guān)性

時間戳:指1970-01-01 00:00:00(GMT/UTC)起到當(dāng)前的毫秒數(shù)。與時區(qū)無關(guān),不同時區(qū)同一個時刻的時間戳是相同的。

  • 當(dāng)UTC時區(qū)的時間為1970-01-01 00:00:00時,時間戳為0
  • 此時UTC+8(東8區(qū))時區(qū)的時間為1970-01-01 08:00:00,時間戳也為0
  • 此時UTC+9(東9區(qū))時區(qū)的時間為1970-01-01 09:00:00,時間戳也為0
    public static void main(String[] args) {
        Date date = new Date(0L);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        System.out.println("時間戳0對應(yīng)時間(UTC):"+sdf.format(date));
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        System.out.println("時間戳0對應(yīng)時間(UTC+8):"+sdf.format(date));
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));
        System.out.println("時間戳0對應(yīng)時間(UTC+9):"+sdf.format(date));
    }

時間戳0對應(yīng)時間(UTC):1970-01-01 00:00:00
時間戳0對應(yīng)時間(UTC+8):1970-01-01 08:00:00
時間戳0對應(yīng)時間(UTC+9):1970-01-01 09:00:00

主要步驟流程圖分析

1. 正確情況流程圖

Java系統(tǒng)時區(qū):Asia/Shanghai(東8區(qū))
JDBC數(shù)據(jù)庫連接時區(qū):serverTimezone=+8
MySQL全局時區(qū):time_zone=+08:00

在這里插入圖片描述

2. 錯誤情況流程圖

Java系統(tǒng)時區(qū):Asia/Shanghai(東8區(qū))
JDBC數(shù)據(jù)庫連接時區(qū):serverTimezone=-5
MySQL全局時區(qū):time_zone=+08:00

在這里插入圖片描述

錯誤情況詳細(xì)分析

Java寫入時間到MySQL服務(wù)端環(huán)節(jié)

Java準(zhǔn)備寫入的時間為:2022-10-15 08:00:00(UTC+8)

JDBC先轉(zhuǎn)化得到Timestamp:2022-10-15 00:00:00(UTC)

注意:時間戳記錄的是UTC時區(qū)的值,與UTC+8時區(qū)的2022-10-15 08:00:00是同一時間

JDBC在將Timestamp格式化為UTC-5時區(qū)(serverTimezone=-5)的時間字符串:2022-10-14 19:00:00,將字符串傳給MySQL服務(wù)端

MySQL服務(wù)端認(rèn)為2022-10-14 19:00:00就是MySQL全局時區(qū)time_zone=+08:00(UTC+8)時區(qū)的時間,存入。

MySQL服務(wù)端返回時間給Java環(huán)節(jié):

MySQL服務(wù)端返回UTC+8時區(qū)的時間字符串:2022-10-14 19:00:00

JDBC誤認(rèn)為該時間是UTC-5時區(qū)(serverTimezone=-5)先將時間字符串轉(zhuǎn)為Timestamp:2022-10-15 00:00:00(UTC)

Java將Timestamp轉(zhuǎn)化為:2022-10-15 00:00:00(UTC+8)

主要步驟源碼分析

① JDBC配置MySQL服務(wù)時區(qū)

如果配置了serverTimezone,則會使用serverTimezone配置的時區(qū)

如果沒配置,會去取數(shù)據(jù)庫中time_zone變量所配置的時區(qū)
具體方法:NativeProtocol類的configureTimezone方法

   public void configureTimezone() {
       String configuredTimeZoneOnServer = this.serverSession.getServerVariable("time_zone");

       if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
           configuredTimeZoneOnServer = this.serverSession.getServerVariable("system_time_zone");
       }
	   // 獲取serverTimezone配置的時區(qū)(PropertyKey.serverTimezone=serverTimezone)
       String canonicalTimezone = getPropertySet().getStringProperty(PropertyKey.serverTimezone).getValue();

       if (configuredTimeZoneOnServer != null) {
           // 如果沒配置serverTimezone,獲取數(shù)據(jù)庫中time_zone變量的時區(qū)
           if (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone)) {
               try {
                   canonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, getExceptionInterceptor());
               } catch (IllegalArgumentException iae) {
                   throw ExceptionFactory.createException(WrongArgumentException.class, iae.getMessage(), getExceptionInterceptor());
               }
           }
       }

       if (canonicalTimezone != null && canonicalTimezone.length() > 0) {
       	   // 設(shè)置服務(wù)時區(qū)
           this.serverSession.setServerTimeZone(TimeZone.getTimeZone(canonicalTimezone));

           if (!canonicalTimezone.equalsIgnoreCase("GMT") && this.serverSession.getServerTimeZone().getID().equals("GMT")) {
               throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("Connection.9", new Object[] { canonicalTimezone }),
                       getExceptionInterceptor());
           }
       }
	   // 設(shè)置默認(rèn)時區(qū)
       this.serverSession.setDefaultTimeZone(this.serverSession.getServerTimeZone());
   }

JDBC創(chuàng)建數(shù)據(jù)庫連接就是使用該時區(qū)。

如果沒配置serverTimezone,獲取數(shù)據(jù)庫中time_zone變量的時區(qū)為CST,就會有問題,因為在java中:TimeZone.getTimeZone("CST")表示的是中央標(biāo)準(zhǔn)時間(美國標(biāo)準(zhǔn)時間)UTC-5(UTC-6)。

CST問題的源頭:

    public SqlTimestampValueFactory(PropertySet pset, Calendar calendar, TimeZone tz) {
        super(pset);
        if (calendar != null) {
            this.cal = (Calendar) calendar.clone();
        } else {
            this.cal = Calendar.getInstance(tz, Locale.US);
            this.cal.setLenient(false);
        }
    }

debug結(jié)果:

在這里插入圖片描述

② Java寫入時間到MySQL服務(wù)端

ClientPreparedStatement類的setTimestamp方法

    @Override
    public void setTimestamp(int parameterIndex, Timestamp x) throws java.sql.SQLException {
        synchronized (checkClosed().getConnectionMutex()) {
            ((PreparedQuery<?>) this.query).getQueryBindings().setTimestamp(getCoreParameterIndex(parameterIndex), x);
        }
    }

ClientPreparedQueryBindings類的setTimestamp方法

    public void setTimestamp(int parameterIndex, Timestamp x, Calendar targetCalendar, int fractionalLength) {
        if (x == null) {
            setNull(parameterIndex);
        } else {

            x = (Timestamp) x.clone();

            if (!this.session.getServerSession().getCapabilities().serverSupportsFracSecs()
                    || !this.sendFractionalSeconds.getValue() && fractionalLength == 0) {
                x = TimeUtil.truncateFractionalSeconds(x);
            }

            if (fractionalLength < 0) {
                fractionalLength = 6;
            }

            x = TimeUtil.adjustTimestampNanosPrecision(x, fractionalLength, !this.session.getServerSession().isServerTruncatesFracSecs());
			// 將時間戳格式化為字符串時間
			// this.session.getServerSession().getDefaultTimeZone() 時區(qū)(未配置serverTimezone,且數(shù)據(jù)庫中time_zone變量的時區(qū)為CST時,這里就是CST時區(qū))
            this.tsdf = TimeUtil.getSimpleDateFormat(this.tsdf, "''yyyy-MM-dd HH:mm:ss", targetCalendar,
                    targetCalendar != null ? null : this.session.getServerSession().getDefaultTimeZone());

            StringBuffer buf = new StringBuffer();
            buf.append(this.tsdf.format(x));
            if (this.session.getServerSession().getCapabilities().serverSupportsFracSecs()) {
                buf.append('.');
                buf.append(TimeUtil.formatNanos(x.getNanos(), 6));
            }
            buf.append('\'');

            setValue(parameterIndex, buf.toString(), MysqlType.TIMESTAMP);
        }
    }

將時間格式化為字符串時間(根據(jù)連接的時區(qū))。

③ MySQL服務(wù)端返回時間給Java

ResultSetImpl類的getTimestamp方法

    public Timestamp getTimestamp(String columnName) throws SQLException {
        return getTimestamp(findColumn(columnName));
    }

    public Timestamp getTimestamp(int columnIndex) throws SQLException {
        checkRowPos();
        checkColumnBounds(columnIndex);
        return this.thisRow.getValue(columnIndex - 1, this.defaultTimestampValueFactory);
    }

SqlTimestampValueFactory類的localCreateFromTimestamp方法

    public Timestamp localCreateFromTimestamp(InternalTimestamp its) {
        if (its.getYear() == 0 && its.getMonth() == 0 && its.getDay() == 0) {
            throw new DataReadException(Messages.getString("ResultSet.InvalidZeroDate"));
        }

        synchronized (this.cal) {
            try {
                // 這里就是關(guān)鍵環(huán)節(jié),this.cal是一個Calendar類,里面有時區(qū)信息(未配置serverTimezone,且數(shù)據(jù)庫中time_zone變量的時區(qū)為CST時,這里就是CST時區(qū))
                this.cal.set(its.getYear(), its.getMonth() - 1, its.getDay(), its.getHours(), its.getMinutes(), its.getSeconds());
                Timestamp ts = new Timestamp(this.cal.getTimeInMillis());
                ts.setNanos(its.getNanos());
                return ts;
            } catch (IllegalArgumentException e) {
                throw ExceptionFactory.createException(WrongArgumentException.class, e.getMessage(), e);
            }
        }
    }

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

相關(guān)文章

  • Java實現(xiàn)List反轉(zhuǎn)的方法總結(jié)

    Java實現(xiàn)List反轉(zhuǎn)的方法總結(jié)

    在Java中,反轉(zhuǎn)一個List意味著將其元素的順序顛倒,使得第一個元素變成最后一個,最后一個元素變成第一個,依此類推,這一操作在處理數(shù)據(jù)集合時非常有用,所以本文給大家總結(jié)了Java實現(xiàn)List反轉(zhuǎn)的方法,需要的朋友可以參考下
    2024-04-04
  • Java中Logger定義的3種方式及最佳實踐

    Java中Logger定義的3種方式及最佳實踐

    這篇文章主要介紹了Java中三種常見的Logger定義方式及其優(yōu)缺點,同時文章還討論了Logger的命名和訪問修飾符的最佳實踐,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-02-02
  • Java Web 實現(xiàn)QQ登錄功能一個帳號同一時間只能一個人登錄

    Java Web 實現(xiàn)QQ登錄功能一個帳號同一時間只能一個人登錄

    對于一個帳號在同一時間只能一個人登錄,下文給大家介紹的非常詳細(xì),對java web qq 登錄功能感興趣的朋友一起看看吧
    2016-11-11
  • Java函數(shù)式編程之通過行為參數(shù)化傳遞代碼

    Java函數(shù)式編程之通過行為參數(shù)化傳遞代碼

    行為參數(shù)化就是可以幫助你處理頻繁變更的需求的一種軟件開發(fā)模式,這篇文章將給大家詳細(xì)的介紹一下Java函數(shù)式編程之行為參數(shù)化傳遞代碼,感興趣的同學(xué)可以參考閱讀下
    2023-08-08
  • java 中數(shù)組初始化實例詳解

    java 中數(shù)組初始化實例詳解

    這篇文章主要介紹了 本文主要講數(shù)組的初始化方法、可變參數(shù)列表以及可變參數(shù)列表對函數(shù)重載的影響的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Java實現(xiàn)矩陣加減乘除及轉(zhuǎn)制等運(yùn)算功能示例

    Java實現(xiàn)矩陣加減乘除及轉(zhuǎn)制等運(yùn)算功能示例

    這篇文章主要介紹了Java實現(xiàn)矩陣加減乘除及轉(zhuǎn)制等運(yùn)算功能,結(jié)合實例形式總結(jié)分析了java常見的矩陣運(yùn)算實現(xiàn)技巧,需要的朋友可以參考下
    2018-01-01
  • 線程池調(diào)用kafka發(fā)送消息產(chǎn)生的內(nèi)存泄漏問題排查解決

    線程池調(diào)用kafka發(fā)送消息產(chǎn)生的內(nèi)存泄漏問題排查解決

    這篇文章主要為大家介紹了線程池調(diào)用kafka發(fā)送消息產(chǎn)生的內(nèi)存泄漏問題排查解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Java線上死鎖問題從定位到解決的全鏈路指南

    Java線上死鎖問題從定位到解決的全鏈路指南

    在分布式系統(tǒng)高并發(fā)場景下,死鎖如同定時炸彈,隨時可能引發(fā)服務(wù)雪崩,本文將分享一套完整的死鎖應(yīng)對策略,結(jié)合實戰(zhàn)案例與生產(chǎn)級解決方案,助你快速化解危機(jī),需要的朋友可以參考下
    2025-06-06
  • Spring Cloud 中@FeignClient注解中的contextId屬性詳解

    Spring Cloud 中@FeignClient注解中的contextId屬性詳解

    這篇文章主要介紹了Spring Cloud 中@FeignClient注解中的contextId屬性詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java 設(shè)計模式之適配器模式詳解

    Java 設(shè)計模式之適配器模式詳解

    設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)。使用設(shè)計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
    2021-11-11

最新評論