圖片
在實際的工作場景中有時候就是一個小小的問題,就可能引發出一個大大的bug。而且工作這么多年,看到的線上事故,往往也都是這些小的細節問題,所以學習這些具有實際經驗的細節非常重要。
有些事故隱藏的很深!
其實很多時候事故也不是一開始就有的,而是隨著需求的迭代,達到某一個條件后觸達到事故的發生條件了才出現的。就像 MySQL 的時區配置問題,它既有不同版本 JDBC 連接引擎的不同,又有數據庫設置的時區,還有服務端設置的時區,還包括在使用數據庫配置時指定的時區。這些條件綜合發生時才會出現事故。
接下來,小傅哥就給大家分享下為啥是 8.0.22 版本才會引發時區錯誤問題。
這是一條很普通的SQL語句;
<insert id="insert" parameterType="cn.bugstack.xfg.dev.tech.infrastructure.po.EmployeePO"> INSERT INTO employee(employee_number, employee_name, employee_level, employee_title, create_time, update_time) VALUES(#{employeeNumber}, #{employeeName}, #{employeeLevel}, #{employeeTitle}, now(), now())</insert>
修改下這條普通的SQL語句;
<insert id="insert" parameterType="cn.bugstack.xfg.dev.tech.infrastructure.po.EmployeePO"> INSERT INTO employee(employee_number, employee_name, employee_level, employee_title, create_time, update_time) VALUES(#{employeeNumber}, #{employeeName}, #{employeeLevel}, #{employeeTitle}, #{createTime}, now())</insert>
接下來在執行插入SQL語句;
圖片
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.22</version></dependency>
jdbc:mysql://127.0.0.1:3306/road-map?useUnicode=true&characterEncoding=utf8&autoRecnotallow=true&zeroDateTimeBehavior=convertToNull&useSSL=true
show variables like '%time_zone%';+------------------+--------+| Variable_name | Value |+------------------+--------+| system_time_zone | CST || time_zone | SYSTEM |+------------------+--------+
美國中部時間 Central Standard Time (USA) UTC-05:00 或 UTC-06:00
澳大利亞中部時間 Central Standard Time (Australia) UTC+09:30
中國標準時 China Standard Time UTC+08:00
古巴標準時 Cuba Standard Time UTC-04:00
[root@lavm-aqhgp9nber ~]# timedatectl Local time: Sat 2024-08-31 13:57:07 CST Universal time: Sat 2024-08-31 05:57:07 UTC RTC time: Sat 2024-08-31 05:57:06 Time zone: Asia/Shanghai (CST, +0800) NTP enabled: yesNTP synchronized: yes RTC in local TZ: no DST active: n/a
命令修改時區;sudo timedatectl set-timezone Asia/Shanghai
命令修改時區;sudo timedatectl set-timezone America/New_York
在 8.0.0 ~ 8.0.22 版本中,如果未配置時區,serverTimeznotallow=Asia/Shanghai 則會取服務端時區,所以如果服務端配置的是 CST 時區,則會有問題。調試源碼;
com.mysql.cj.protocol.a.NativeProtocol#configureTimezone
圖片
在 8.0.23 版本以后,如果未配置時區,調整為獲取客戶端時區。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version></dependency>
com.mysql.cj.protocol.a.NativeProtocol#configureTimezone
圖片
地址:https://dev.mysql.com/doc/relnotes/connector-j/en/news-8-0-23.html
Bugs Fixed
After upgrading from Connector/J 5.1 to 8.0, the results of saving and then retrieving DATETIME and TIMESTAMP values became different sometimes. It was because while Connector/J 5.1 does not preserve a time instant by default, Connector/J 8.0.22 and earlier tried to do so by converting a timestamp to the server's session time zone before sending its value to the server. In this release, new mechanisms for controlling timezone conversion has been introduced—see Preserving Time Instants for details. Under this new mechanism, the default behavior of Connector/J 5.1 in this respect is preserved by setting the connection property preserveInstants=false. (Bug #30962953, Bug #98695, Bug #30573281, Bug #95644)
從 Connector/J 5.1 升級到 8.0 后,保存和檢索 DATETIME 和 TIMESTAMP 值的結果有時會有所不同。這是因為,雖然 Connector/J 5.1 默認不保留時間點,但 Connector/J 8.0.22 及更早版本嘗試通過在將時間戳的值發送到服務器之前將其轉換為服務器的會話時區來保留時間點。在此版本中,引入了用于控制時區轉換的新機制 - 有關詳細信息,請參閱保留時間點。在這種新機制下,通過設置連接屬性 retainInstants=false 來保留 Connector/J 5.1 在這方面的默認行為。(錯誤 #30962953、錯誤 #98695、錯誤 #30573281、錯誤 #95644)
在使用MySQL的時候,確保服務器時區、MySQL時區、Java應用鏈接MySQL JDBC的參數配置,都指定到具體的時區上。MySQL JDBC 使用 8.0.23+ 版本,不要使用 8.0.0 ~ 8.0.22 版本,尤其是5.1升級要升級到 8.0.23 以及往后的版本。
正確配置;url: jdbc:mysql://127.0.0.1:3306/road-map?useUnicode=true&characterEncoding=utf8&autoRecnotallow=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimeznotallow=Asia/Shanghai
本文鏈接:http://www.tebozhan.com/showinfo-26-112721-0.html是什么導致了,寫入MySQL庫表時間不正確?—— 官網也有Bug!
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
下一篇: 盤點分頁查詢中遇到的坑!