[轉帖]關於mysql的時區(下):如何設置mysql的時區

一、如何設置 mysql 時區

1、命令

1)查時區:show variables like '%time_zone%'

返回有2行記錄,要看time_zone變量的值,不需要看system_time_zone。

若值爲SYSTEM表示取值跟system_time_zone保持一致。

system_time_zone的值是啓動mysql服務的時候讀取了操作系統的值,除非重新啓動mysql服務重讀否則這個值不變

還有一種查時區的方法,select @@GLOBAL.time_zone,@@SESSION.time_zone 可以查出全局的時區以及會話時區。

2)設置會話時區:set time_zone='+8:00'

僅對當前會話有效,在當前窗口立即生效,關閉會話窗口後設置失效。無需重新登錄會話生效,也無需關閉窗口再開窗口

  • 執行後如果不確定是否設置成功,可以用上面提到過的語句查查看

  • 允許取值:'+08:00',兼容了多0

    As a string indicating an offset from UTC of the form [*H*]*H*:*MM*, prefixed with a + or -, such as '+10:00', '-6:00', or '+05:30'. A leading zero can optionally be used for hours values less than 10; MySQL prepends a leading zero when storing and retriving the value in such cases.

  • 允許取值SYSTEM:set time_zone='SYSTEM'

3)設置全局時區:set global time_zone='+8:00

全局會話有效。必須重新連接才生效(比如exit後重新mysql -uroot -p進行連接)。無需重啓mysql服務,重啓 mysql 服務後丟失。

網上貼的是兩個語句,需要 flush privileges,但是實際測試即使flush了也還是需要重新連接會話纔會生效,而且看了下官網,沒flush的語句。而且實測不需要flush只需要重連

4)修改 mysql 的配置文件永久設置時區

需要重啓 mysql 服務後才能生效,這個對比上面的全局設置,即使服務重啓也是能保持配置。配置後跟數據庫所在的操作系統的時區就獨立開了。

// 下面是5.7的mysql配置,我看了一下8.x版本的mysql也是同樣的配置,不過mysql 8.x 默認就是 utf8mb4了,所以字符設置的那行就不需要了
// 配置的位置,無論5.7還是8.x版本,都必須配在 [mysqld] 下面
[mysqld]
default-time-zone=+08:00
character-set-server=utf8mb4

    2、如何查看並讀懂這些命令

    1)、解讀查時區的命令返回的結果
    +------------------+--------+
    | Variable_name    | Value  |
    +------------------+--------+
    | system_time_zone | CST    |
    | time_zone        | +08:00 |
    +------------------+--------+
    
      • 要知道mysql當前在什麼時區,看哪個變量?

        看 time_zone。不看 system_time_zone。如要修改時區,直接修改 time_zone,無視 system_time_zone

      • time_zone 的值如果是 SYSTEM 表示什麼?

        表示跟 system_time_zone 取值一樣。安裝MySQL後默認就是SYSTEM。

        有些地方會表述成 SYSTEM 的含義是 "時區跟隨操作系統","跟隨操作系統和跟隨system_time_zone" 其實是一樣的意思,因爲 system_time_zone 就是啓動mysql服務的時候讀取了操作系統的時區的值。
        
        • 建議time_zone不要設置成 SYSTEM

          因爲如果 system_time_zone 的值是CST,CST被Java認爲是美國的時間,造成混亂。參考後面由此引起的bug

        • system_time_zone 的值是怎麼來的?

          它的值來自mysql服務啓動時讀取操作系統時區,讀取後即使修改操作系統的時區,它的值也不會再改變了,除非重啓mysql 服務變量重新讀取

        • system_time_zone 的值能改變嗎?

          不能通過命令改變

          mysql> set system_time_zone='JST';
          ERROR 1238 (HY000): Variable 'system_time_zone' is a read only variable
          
          • 如何確定CST代表什麼時區?

            由於中國和美國的時區同名,要知道CST究竟代表什麼時區,最簡單的方法是 select now() 跟你手機的時間對比一下

          3、探討一個問題

          如果OS是東八區,mysql服務起來了,time_zone值是SYSTEM,system_time_zone值是CST(東八區),此時連上mysql獲取的時間是東八區的,接着修改OS的時區爲東九區,斷開mysql連接的會話並重新連接會話,問此時獲取的時間是什麼時區的? (實測還是東八區)

          這個問題的本質就是:time_zone的SYSTEM的值的含義,究竟是跟隨啓動mysql服務就確定下來的system_time_zone的值呢? 還是跟隨操作系統的變化而變化。

          實際測試,是跟隨system_time_zone變量的變化而變化,而非系統,也就是說time_zone是SYSTEM值,只跟system_time_zone變量有關。而system_time_zone僅僅是啓動mysql服務的時候操作系統的一個時區的快照值而已(那一瞬間的值)

          4、噁心的CST(修改time_zone改成非SYSTEM!)

          CST同名的有4個時區

          • Central Standard Time (USA) UT-6:00 美國標準時間
          • Central Standard Time (Australia) UT+9:30 澳大利亞標準時間
          • China Standard Time UT+8:00 中國標準時間
          • Cuba Standard Time UT-4:00 古巴標準時間

          這個不僅僅是重名的問題,而且在某些情況下會造成bug,詳細看另一篇博文。這裏簡單說一下

          CST 時區是個非常坑的概念,因爲在 mysql 裏被理解爲 China Standard Time(GMT+8),但是在Java裏被理解爲Central Standard Time (USA)(GMT-6),這就是造成坑的原因。解決辦法是mysql就別用CST時區,改成 +08:00 以免造成誤解。(肯定改mysql啦,你改得了jdk源碼嗎?)

          如果mysql的time_zone變量是SYSTEM,而system_time_zone是CST的值,system_time_zone的CST這個字符串會造成bug。

          mysql的jdbc驅動的代碼裏會設置時區,這個時區是通過 TimeZone.getTimeZone(canonicalTimezone) 讀取,其中 canonicalTimezone 是字符串, TimeZone.getTimeZone("CST") 返回-6時區,即美國的時區。

          在這裏插入圖片描述

          解決辦法

          • 數據庫設置time_zone的值爲非SYSTEM,比如+08:00
          • spring/springboot等程序連接的時候,jdbcUrl帶上時區,比如jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai

          參考資料

          https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html

          https://dev.mysql.com/doc/refman/5.7/en/datetime.html

          文章知識點與官方知識檔案匹配,可進一步學習相關知識
          發表評論
          所有評論
          還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
          相關文章