日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

数据库时区那些事儿 - MySQL的时区处理

發(fā)布時間:2023/12/6 数据库 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库时区那些事儿 - MySQL的时区处理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文地址

當(dāng)JVM時區(qū)和數(shù)據(jù)庫時區(qū)不一致的時候,會發(fā)生什么?這個問題也許你從來沒有注意過,但是當(dāng)把Java程序容器化的時候,問題就浮現(xiàn)出來了,因為目前幾乎所有的Docker Image的時區(qū)都是UTC。本文探究了MySQL及其JDBC驅(qū)動對于時區(qū)的處理方式,并嘗試給出最佳實踐。

先給總結(jié)

  • DATE和TIME類型不支持時區(qū)轉(zhuǎn)換。
  • 對于TIMESTAMP類型,MySQL會正確的根據(jù)connection時區(qū)(對于JDBC來說就是JVM時區(qū))/服務(wù)端時區(qū)做轉(zhuǎn)換。

    • JDBC程序不需要特別注意什么事情。只要保證JVM時區(qū)和用戶所在時區(qū)保持一致即可。
  • 不要在服務(wù)器端做日期時間的字符串格式化(DATE_FORMAT()),因為返回的結(jié)果是服務(wù)端的時區(qū),而不是connection的時區(qū)(對于JDBC來說就是JVM時區(qū))。
  • CURRENT_TIMESTAMP(), CURRENT_TIME(), CURRENT_DATE()可以安全的使用,返回的結(jié)果會轉(zhuǎn)換成connection時區(qū)(對于JDBC來說就是JVM時區(qū))。
  • CURRENT_TIME()有一個不知道是不是BUG的Bug #92453。

日期時間類型的時區(qū)

MySQL - The DATE, DATETIME, and TIMESTAMP Types:

MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the
current time zone for retrieval. (This does not occur for other types such as DATETIME.)
By default, the current time zone for each connection is the server's time. The time zone can be set on
a per-connection basis.
As long as the time zone setting remains constant, you get back the same value you store.
If you store a TIMESTAMP value, and then change the time zone and retrieve the value, the retrieved value
is different from the value you stored. This occurs because the same time zone was not used for conversion
in both directions.

簡而言之就是兩句話:

  • 查詢TIMESTAMP類型所返回的值,會根據(jù)connection的時區(qū)(對于JDBC來說就是JVM時區(qū))做轉(zhuǎn)換
  • 在MySQL中只有TIMESTAMP類型會做時區(qū)轉(zhuǎn)換
  • 為了驗證這個結(jié)論,我寫了一段程序來實驗,這個程序做了三件事情:

  • 使用Asia/Shanghai時區(qū)構(gòu)造一個日期java.util.Date:2018-09-14 10:00:00,然后插入到數(shù)據(jù)庫里(表:test,列:timestamp類型)
  • 使用Asia/Shanghai時區(qū)把這個值再查出來,看看結(jié)果。
  • 使用Asia/Shanghai時區(qū),獲得這個字段的格式化字符串(使用DATE_FORMAT()函數(shù))。
  • 使用Europe/Paris時區(qū)重復(fù)第2-3步的動作
  • 在運行程序之前,我們先用Docker啟動一個MySQL,它所在的MySQL的時區(qū)是UTC(除非特別設(shè)定,所有Docker Image時區(qū)都默認(rèn)為UTC):

    docker run --name mysql-timezone-test \-e MYSQL_RANDOM_ROOT_PASSWORD=yes \-e MYSQL_DATABASE=testdb \-e MYSQL_USER=tz \-e MYSQL_PASSWORD=tz \-p 3306:3306 \-d mysql:8

    下面是結(jié)果:

    Insert data, Time Zone : 中國標(biāo)準(zhǔn)時間 java.util.Date : 2018-09-14 10:00:00 Insert into timestamp column : 2018-09-14 10:00:00 -------------------- Retrieve data, Time Zone : 中國標(biāo)準(zhǔn)時間 Retrieve java.util.Date : 2018-09-14 10:00:00 Retrieve formatted string : 2018-09-14 02:00:00 -------------------- Retrieve data, Time Zone : 中歐時間 Retrieve java.util.Date : 2018-09-14 04:00:00 Retrieve formatted string : 2018-09-14 02:00:00

    可以看到Retrieve java.util.Date返回的結(jié)果根據(jù)JVM時區(qū)做了轉(zhuǎn)換的。而Retrieve formatted string返回的結(jié)果則是UTC時間。

    當(dāng)前日期時間相關(guān)函數(shù)

    MySQL與"當(dāng)前日期時間"相關(guān)的函數(shù)有這么些,MySQL - Date and Time Functions:

    The CURRENT_TIMESTAMP(), CURRENT_TIME(), CURRENT_DATE(), and FROM_UNIXTIME() functions return values
    in the connection's current time zone, which is available as the value of the time_zone system variable.

    而且根據(jù)文檔所講,它們返回的結(jié)果匹配當(dāng)前連接所設(shè)定的時區(qū)。

    為了驗證這個結(jié)論,同樣寫了一段程序,分別使用Asia/Shanghai和Europe/Paris來調(diào)用CURRENT_TIMESTAMP()、CURRENT_TIME()、CURRENT_DATE()。

    下面是運行結(jié)果:

    JVM Time Zone : 中國標(biāo)準(zhǔn)時間 Test CURRENT_DATE() : 2018-09-18 Test CURRENT_TIME() : 10:55:41 Test CURRENT_TIMESTAMP() : 2018-09-18 10:55:41.0 -------------------- JVM Time Zone : 中歐時間 Test CURRENT_DATE() : 2018-09-18 Test CURRENT_TIME() : 03:56:02 Test CURRENT_TIMESTAMP() : 2018-09-18 04:56:02.0

    可以看到結(jié)果是基本符合文檔里的說明的,但是要注意,在Europe/Paris時區(qū),CURRENT_TIME()和CURRENT_TIMESTAMP()的時間部分相差一小時。
    看上去CURRENT_TIMESTAMP()返回的是UTC DST offset結(jié)果,而CURRENT_TIME()返回的是UTC offset結(jié)果,關(guān)于這個我登記了Bug #92453。
    關(guān)于Europe/Paris的DST信息可以在這里找到Wiki - List of tz database time zones。

    在MySQL客戶端操作時區(qū)

    -- 查詢系統(tǒng)時區(qū)和session時區(qū) SELECT @@global.time_zone, @@session.time_zone;-- 設(shè)置session時區(qū) SET time_zone = 'Asia/Shanghai';

    詳見:MySQL Server Time Zone Support

    Docker啟動時設(shè)定時區(qū)

    你可以在docker啟動的時候設(shè)定MySQL容器的時區(qū),比如這樣-e TZ=Asia/Shanghai。

    這個方法有問題,會出現(xiàn)時間錯亂,workaround是root用戶連接到MySQL,然后執(zhí)行SET GLOBAL time_zone = 'Asia/Shanghai';。

    這樣客戶端連接MySQL時,查詢的時間的時區(qū)都是Asia/Shanghai了。

    參考資料

    • MySQL - The DATE, DATETIME, and TIMESTAMP Types
    • MySQL - Date and Time Functions
    • MySQL Server Time Zone Support
    • Wiki - List of tz database time zones
    • W3C- Working with timezone

    相關(guān)代碼

    https://github.com/chanjarste...

    總結(jié)

    以上是生活随笔為你收集整理的数据库时区那些事儿 - MySQL的时区处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。