最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL?時區(qū)與?serverTimezone詳解

 更新時間:2024年12月20日 09:01:19   作者:AaronLin  
存儲?TIMESTAMP?類型數(shù)據(jù)時,MySQL 會根據(jù)當前會話的時區(qū)將時間轉換為 UTC 時間,MySQL 實際存儲的是 UTC 時間,這篇文章主要介紹了MySQL?時區(qū)與?serverTimezone,需要的朋友可以參考下

TL;DR

  • 手動為 MySQL 指定非偏移量的時區(qū),以避免 TIMESTAMP 類型夏令時問題和時區(qū)轉化性能瓶頸
  • TIMESTAMP 范圍:'1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07'
  • 連接 MySQL 數(shù)據(jù)庫時,serverTimezone 參數(shù)用于指定數(shù)據(jù)庫服務器的時區(qū),需要設置為與 MySQL 服務端相同的時區(qū)

MySQL 時區(qū)設置影響 TIMESTAMP 類型數(shù)據(jù)和部分時間函數(shù)

MySQL 會話時區(qū)設置會影響 TIMESTAMP 和 時間函數(shù)(NOW()、CURDATE()、CURTIME()、CURRENT_TIMESTAMP())

存儲 TIMESTAMP 類型數(shù)據(jù)時,MySQL 會根據(jù)當前會話的時區(qū)將時間轉換為 UTC 時間,MySQL 實際存儲的是 UTC 時間。檢索時 MySQL 根據(jù)會話的時區(qū)將存儲的 UTC 時間轉換為會話對應時區(qū)的時間。而 DATETIME 類型的字段存儲的時間值是原始值,不受時區(qū)影響

MySQL 默認使用 SYSTEM 時區(qū)(即操作系統(tǒng)的時區(qū)),每個需要時區(qū)計算的 MySQL 函數(shù)調用都會調用系統(tǒng)庫來確定當前系統(tǒng)時區(qū)。此調用可能受到全局互斥體的保護,從而導致爭用,建議顯式設置時區(qū)

查詢當前時區(qū)

# time_zone:MySQL 使用 SYSTEM 的時區(qū)
# system_time_zone:SYSTEM 為 CST 時區(qū)
show variables like "%time_zone%";
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | SYSTEM |
+------------------+--------+

不同會話時區(qū)對 時間函數(shù) 的影響

# 當前時區(qū) 
# 查看當前的全球和會話時區(qū)值
SELECT @@GLOBAL.time_zone, @@SESSION.time_zone;
SELECT NOW(), CURDATE(), CURTIME(), CURRENT_TIMESTAMP();
set time_zone = 'America/New_York';
SELECT NOW(), CURDATE(), CURTIME(), CURRENT_TIMESTAMP();

不同會話時區(qū)對 TIMESTAMP 類型的影響

# UTC +8
set time_zone = 'Asia/Shanghai';
CREATE TABLE events (
    id INT AUTO_INCREMENT PRIMARY KEY,
    event_name VARCHAR(255) NOT NULL,
    event_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    event_datetime DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO events (event_name, event_timestamp, event_datetime) VALUES ('10.24 15:45:00', '2022-10-24 15:45:00', '2022-10-24 15:45:00');
INSERT INTO events (event_name, event_timestamp, event_datetime) VALUES ('12.24 15:45:00', '2022-12-24 15:45:00', '2022-12-24 15:45:00');
SELECT * FROM events;
+----+----------------+---------------------+---------------------+
| id | event_name     | event_timestamp     | event_datetime      |
+----+----------------+---------------------+---------------------+
|  1 | 10.24 15:45:00 | 2022-10-24 15:45:00 | 2022-10-24 15:45:00 |
|  2 | 12.24 15:45:00 | 2022-12-24 15:45:00 | 2022-12-24 15:45:00 |
+----+----------------+---------------------+---------------------+
2 rows in set (0.00 sec)
# 僅修改當前會話的時區(qū)
set time_zone = 'America/New_York';
SELECT * FROM events;
+----+----------------+---------------------+---------------------+
| id | event_name     | event_timestamp     | event_datetime      |
+----+----------------+---------------------+---------------------+
|  1 | 10.24 15:45:00 | 2022-10-24 03:45:00 | 2022-10-24 15:45:00 |    <- 夏令時,相差 12 小時
|  2 | 12.24 15:45:00 | 2022-12-24 02:45:00 | 2022-12-24 15:45:00 |    <- 平時相差 13 小時
+----+----------------+---------------------+---------------------+
2 rows in set (0.00 sec)

紐約 UTC 時差通常為 UTC-5(EST),夏令時為 UTC-4(EDT),所以將原本的會話從上海(UTC+8) 轉到紐約時,TIMESTAMP 相差了 13 或 12(夏令時) 小時,所以為了自動轉換夏令時,指定時區(qū)最好使用時區(qū)名詞 Asia/Shanghai,避免使用偏移量:'+08:00'

JDBC 連接 MySQL 時 serverTimezone 對于 TIMESTAMP 類型的影響

連接 MySQL 時我們使用 URL:jdbc:mysql://192.168.1.2:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai

這里的 serverTimezone 參數(shù)用于指定連接到 MySQL 數(shù)據(jù)庫時所使用的時區(qū),不顯示指定使用 JVM 默認時區(qū)

MySQL 服務端處理 TIMESTAMP :寫入時根據(jù)會話時區(qū)轉為 UTC 時間戳存儲,讀取時將 UTC 還原為會話時區(qū)的時間,保證了寫入和讀取數(shù)據(jù)的一致。數(shù)據(jù)庫會話時區(qū)與 JVM 時區(qū)相同時,JVM 讀寫的 TIMESTAMP 一致,如果不一致就會出現(xiàn)問題,serverTimezone 就是為了告訴 JDBC 從 MySQL 服務端獲取到的 TIMESTAMP 是什么時區(qū),知道了它所使用的時區(qū),JDBC 就可以進行預處理

MyBatis 在處理 TIMESTAMP 類型的數(shù)據(jù)時會有一些差異,實體映射為 Timestamp 或 Date 在讀寫時會進行上面提到的預處理,而 LocalDateTime 則不會

JDBC 讀取 TIMESTAMP 類型數(shù)據(jù)時

JDBC 執(zhí)行命令時,調用不同的 ResultSet 方法會有不同結果:

  • ResultSet 的 getString 方法:直接讀取時間,即直接返回 數(shù)據(jù)庫根據(jù)會話時區(qū)轉化后的時間
  • ResultSet 的 getTimestamp 方法:將 數(shù)據(jù)庫根據(jù)會話時區(qū)轉化后的時間 根據(jù) serverTimezone 設置的時區(qū)進行轉化,得到 數(shù)據(jù)庫根據(jù)會話時區(qū)轉化后的時間 對應的 UTC 時間毫秒戳,然后將這個 UTC 毫秒時間戳轉換為 Timestamp 類型(它本身不包含時區(qū)信息),打印時會根據(jù) JVM 的時區(qū)轉化為對應的時區(qū)時間

getTimestamp 轉化 Timestamp 的源碼在:com.mysql.cj.result.SqlTimestampValueFactory

這里的 this.connectionTimeZone 就是連接 url 中指定的 serverTimezone

假設 MySQL 默認設置的會話時區(qū)為 Asia/Shanghai,通過默認會話讀取該 TIMESTAMP 的值為:2022-10-24 15:45:00。而 MySQL 實際存儲的 TIMESTAMP 為 UTC 時間:2022-10-24 07:45:00。MySQL JDBC 驅動通過默認會話獲取該值時,MySQL 會自動根據(jù)默認時區(qū)提供轉化好時間:2022-10-24 15:45:00,驅動則會根據(jù) serverTimezone 配置的時區(qū),將 MySQL 的時間轉化為 Calendar 對象,通過 c.getTimeInMillis() 獲取對應的 UTC 時間戳,用于創(chuàng)建 Timestamp 對象

JDBC 寫入 TIMESTAMP 類型:

  • now()寫入,數(shù)據(jù)庫 server 端會獲取數(shù)據(jù)庫當前時區(qū)
  • 按照字符串寫入:MySQL 服務端根據(jù)會話時區(qū)轉成對應的 UTC 毫秒數(shù)存儲
  • 通過變量綁定寫入:傳入 Timestamp 對象,JDBC 將其編碼為 serverTimezone 所代表的時間字符串,類似:2022-06-22 03:29:29,然后發(fā)送給 MySQL 服務端

驗證

import org.junit.jupiter.api.Test;
import java.sql.*;
import java.util.TimeZone;
public class JDBCTest {
    private static String url = "jdbc:mysql://host:3306/mydb?useSSL=false&serverTimezone=UTC";
    private static String username = "root";
    private static String password = "";
    @Test
    void testInsertTimestamp() {
        TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
        try (Connection connection = DriverManager.getConnection(url, username, password); PreparedStatement ps = connection
                .prepareStatement("insert into events(id,event_name,event_timestamp,event_datetime) values (1,'now()',now(),now())");) {
            ps.execute();
        }catch (Exception e){
            e.printStackTrace();
        }
        try (Connection connection = DriverManager.getConnection(url, username, password); PreparedStatement ps = connection
                .prepareStatement("insert into events(id,event_name,event_timestamp,event_datetime) values (2,'2022-06-22 03:29:29','2022-06-22 03:29:29', '2022-06-22 03:29:29')");) {
            ps.execute();
        }catch (Exception e){
            e.printStackTrace();
        }
        try (Connection connection = DriverManager.getConnection(url, username, password); PreparedStatement ps = connection
                .prepareStatement("insert into events(id,event_name,event_timestamp,event_datetime) values (3,'1733539800000L',?,?)")) {
            // Sat Dec 07 2024 02:50:00 GMT+0000
            // Sat Dec 07 2024 10:50:00 GMT+0800 (中國標準時間)
            long timestamp = 1733539800000L;
            Timestamp ts1 = new Timestamp(timestamp);
            Timestamp ts2 = new Timestamp(timestamp);
            ps.setTimestamp(1, ts1);
            ps.setTimestamp(2, ts2);
            ps.execute();
            // 根據(jù) serverTimezone 將 Timestamp 預處理為 UTC 時間:2024-12-07 02:50:00
            // 相當于執(zhí)行下列 SQL
            // insert into events(id,event_name,event_timestamp,event_datetime) values (3,'1733539800000L','2024-12-07 02:50:00','2024-12-07 02:50:00')
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Test
    void testGetTimestamp() {
        TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
        try (Connection connection = DriverManager.getConnection(url, username, password); PreparedStatement ps = connection
                .prepareStatement("select * from events where id=3"); ResultSet rs = ps.executeQuery();) {
            while (rs.next()) {
                // getTimestamp is 2024-12-07 10:50:00.0
                // 根據(jù) serverTimezone,認定數(shù)據(jù)庫時區(qū)為 UTC,轉化為 本地 Asia/Shanghai 需要 +8,則預處理為:2024-12-07 10:50:00.0
                System.out.println("getTimestamp is " + rs.getTimestamp("event_timestamp"));
                // getString is 2024-12-07 02:50:00
                System.out.println("getString is " + rs.getString("event_datetime"));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

實驗環(huán)境:
MySQL 8.0.40
mysql-connector-j 9.1.0
mybatis-spring-boot-starter 3.0.4

參考資料

7.1.15 MySQL Server Time Zone Support

13.2.2 The DATE, DATETIME, and TIMESTAMP Types

一文講透MySQL driver讀取時間時的時區(qū)處理

修改mysql時區(qū)的三種方法

MySQL 中存儲時間的最佳實踐

到此這篇關于MySQL 時區(qū)與 serverTimezone的文章就介紹到這了,更多相關mysql  serverTimezone內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • MySQL 基于時間點的快速恢復方案

    MySQL 基于時間點的快速恢復方案

    這篇文章主要介紹了MySQL 基于時間點的快速恢復方案,幫助大家更好的理解和使用MySQL,感興趣的朋友可以了解下
    2020-11-11
  • MySQL的match函數(shù)在sp中使用BUG解決分析

    MySQL的match函數(shù)在sp中使用BUG解決分析

    這篇文章主要為大家介紹了MySQL的match函數(shù)在sp中使用BUG解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • mysql記錄根據(jù)日期字段倒序輸出

    mysql記錄根據(jù)日期字段倒序輸出

    這篇文章主要介紹了mysql記錄根據(jù)日期字段倒序輸出 的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-07-07
  • mysql 前幾條記錄語句之(limit)

    mysql 前幾條記錄語句之(limit)

    mysql 的 top 方法 limit,用來獲取數(shù)據(jù)庫查詢的前幾天記錄。
    2009-11-11
  • MySQL?搭建主從同步實現(xiàn)操作

    MySQL?搭建主從同步實現(xiàn)操作

    這篇文章主要介紹了MySQL?中的主從同步實現(xiàn)操作,文章圍繞如何搭建主從同步詳細展開內容,需要的小伙伴可以參考一下,希望對你有所幫助
    2022-03-03
  • mysql注入之長字符截斷,orderby注入,HTTP分割注入,limit注入方式

    mysql注入之長字符截斷,orderby注入,HTTP分割注入,limit注入方式

    這篇文章主要介紹了mysql注入之長字符截斷,orderby注入,HTTP分割注入,limit注入方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • MySQL與JDBC之間的SQL預編譯技術講解

    MySQL與JDBC之間的SQL預編譯技術講解

    這篇文章主要介紹了MySQL與JDBC之間的SQL預編譯技術講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • MySQL8.0鎖等待排查的實現(xiàn)

    MySQL8.0鎖等待排查的實現(xiàn)

    MySQL8.0相較于5.7版本在鎖等待排查方面發(fā)生了顯著變化,原有的INNODB_LOCKS和INNODB_LOCK_WAITS表被移除,本篇文章將結合這些改動,介紹 MySQL 8.0 版本如何排查鎖等待問題,感興趣的可以了解一下
    2024-09-09
  • MySQL因配置過大內存導致無法啟動的解決方法

    MySQL因配置過大內存導致無法啟動的解決方法

    這篇文章主要給大家介紹了關于MySQL因配置過大內存導致無法啟動的解決方法,文中給出了詳細的解決示例代碼,對遇到這個問題的朋友們具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • 簡述mysql監(jiān)控組復制

    簡述mysql監(jiān)控組復制

    這篇文章主要介紹了mysql監(jiān)控組復制的相關資料,幫助大家更好的理解和學習mysql,感興趣的朋友可以了解下
    2020-08-08

最新評論

竹北市| 运城市| 东兴市| 荔波县| 徐闻县| 水城县| 施秉县| 萨嘎县| 米林县| 开原市| 疏附县| 鹤山市| 武安市| 手机| 岳阳县| 九寨沟县| 浦江县| 洛南县| 华宁县| 青川县| 乐至县| 林芝县| 鹤庆县| 泸水县| 青海省| 巫山县| 东安县| 尚志市| 莆田市| 六安市| 奈曼旗| 临夏市| 泽州县| 合江县| 通州区| 聊城市| 鸡东县| 黄山市| 连平县| 赣州市| 泗阳县|