Mysql - 數據庫時區是客戶端屬性還是服務端屬性

一、說明

同事問我數據庫的時區是客戶端屬性還是服務端屬性,我覺得這個問題十分有意思,之前沒怎麼留意,自己來做下實驗。
首先介紹幾個術語。
GMT(Greenwich Mean Time),格林尼治平均時間。
UTC(Coordinated Universal Time),協調世界時。
CST(China Standard Time),中國標準時間,也稱北京時間。
根據維基百科,格林尼治標準時間的正午是指當平太陽橫穿格林尼治子午線時(也就是在格林尼治上空最高點時)的時間。由於地球每天的自轉是有些不規則的,而且正在緩慢減速,因此格林尼治平時基於天文觀測本身的缺陷,目前已經被原子鐘報時的協調世界時(UTC)所取代。協調世界時是世界上調節時鐘和時間的主要時間標準,計算機中的網絡時間協議(NTP, Network Time Protocol)就是用的協調世界時。不過,GMT和UTC相差不超過1秒,對絕大多數系統來說,可以認爲這兩個時間等價。中國的標準時間就是在UTC上面加8小時。

二、測試

測試使用Mysql8,CentOS7,Jdbc

我現在的時間是北京時間 2023-4-22 19:42,我將服務器的時間設置成任意一個時間,時區設置成東京,即(UTC+9)。

[root@xbz ~]# timedatectl list-timezones  // 列出所有時區
[root@xbz ~]# timedatectl set-timezone Asia/Tokyo  // 設置成東京時區
[root@xbz ~]# date -s '2023-4-20 15:00:00'  // 設置任意時間
[root@xbz ~]# date -R  // 查看系統時間
Thu, 20 Apr 2023 15:00:41 +0900 

將Mysql數據庫重啓,Mysql關於時區有兩個參數
system_time_zone 系統時區,在Mysql啓動時會檢查當前系統的時區並根據系統時區設置。參數不可修改。
time_zone 會話時區,默認爲system,即使用全局參數system_time_zone的值。可以動態修改。

(root@localhost)[(none)]> show variables like '%zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | JST    |
| time_zone        | SYSTEM |
+------------------+--------+

會話時區的修改可以使用命令set global time_zone='+8:00'修改,或者在參數文件中設置default_time_zone='+8:00'。爲了實驗,我將客戶端的時區設置爲'+11:00'。

(root@localhost)[(none)]> set global time_zone='+11:00';
(root@localhost)[(none)]> show variables like '%zone%';  // 再開一個窗口查詢
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | JST    |
| time_zone        | +11:00 |
+------------------+--------+

數據庫服務器在UTC+9,數據庫客戶端時區設置的是UTC+11。分別查服務器的時間和數據庫的時間,數據庫的時間相比服務器的時間要快了2小時,這就是參數time_zone在起作用。

[root@xbz ~]# date -R
Thu, 20 Apr 2023 15:10:58 +0900

([email protected])[(none)]> select sysdate();
+---------------------+
| sysdate()           |
+---------------------+
| 2023-04-20 17:10:45 |
+---------------------+

再來看一個例子,我在數據庫中分別創建一個datetime和timestamp兩個字段,插入同一個時間。然後將客戶端的時區換一下,會發現timestamp的時間也跟着發生變化了,這其實是由於MySQL將timestamp列的值從當前時區轉換爲UTC時間進行存儲,查詢時,將數據從UTC轉換爲檢索的當前時區。

([email protected])[hello]> create table t1(id int, dt datetime, tt timestamp);
([email protected])[hello]> insert into t1 values (1, '2022-01-01 12:00:00', '2022-01-01 12:00:00');
([email protected])[hello]> select * from t1;
+------+---------------------+---------------------+
| id   | dt                  | tt                  |
+------+---------------------+---------------------+
|    1 | 2022-01-01 12:00:00 | 2022-01-01 12:00:00 |
+------+---------------------+---------------------+

([email protected])[hello]> set time_zone='+12:00';
([email protected])[hello]> select * from t1;
+------+---------------------+---------------------+
| id   | dt                  | tt                  |
+------+---------------------+---------------------+
|    1 | 2022-01-01 12:00:00 | 2022-01-01 13:00:00 |
+------+---------------------+---------------------+

接下來測試下Jdbc中的表現

public class JdbcTimeZoneTest {
    public static void main(String[] args) throws Exception {
        String user = "scott";
        String password = "tiger";
        String driver = "com.mysql.cj.jdbc.Driver";
        String url = "jdbc:mysql://192.168.1.82/hello";  
        Class.forName(driver);
        Connection connection = DriverManager.getConnection(url, user, password);
        String sql = "select sysdate()";
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()) {
            System.out.println(resultSet.getTimestamp(1));
        }
    }
}

運行結果:
2023-04-20 19:02:44.0

mysql客戶端的結果:

([email protected])[(none)]> select sysdate();
+---------------------+
| sysdate()           |
+---------------------+
| 2023-04-20 19:02:47 |
+---------------------+

可以看到jdbc跟mysql客戶端顯示的時間一致。

url加入這個參數?serverTimezone=Asia/Shanghai
運行結果:
2023-04-20 19:03:19.0
可以看到時間好像沒什麼變化

當我把jdbc所運行的機器時間調整成(UTC+3)
微信截圖_20230418170911.png

再運行一次,結果:
2023-04-20 14:04:17.0

mysql客戶端的結果:

([email protected])[(none)]> select sysdate();
+---------------------+
| sysdate()           |
+---------------------+
| 2023-04-20 19:04:35 |
+---------------------+

jdbc所顯示的時間爲什麼會比mysql客戶端顯示的時間慢5個小時呢,這是由於serverTimezone=Asia/Shanghai是在東八區,而我的本機設置的時區是東三區,差了5個小時,所以相較於Mysql客戶端就有5個小時的差距。所以serverTimezone要麼不設置,要麼設置成jdbc所運行的機器的時區。

三、總結

  1. 設置好服務器的時區和mysql的時區,避免一些不必要的坑。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章