老生常談!數據庫如何存儲時間?你真的知道嗎?

咱們平時開發中不可避免的就是要存儲時間,好比咱們要記錄操做表中這條記錄的時間、記錄轉帳的交易時間、記錄出發時間等等。你會發現這個時間這個東西與咱們開發的聯繫仍是很是緊密的,用的好與很差會給咱們的業務甚至功能帶來很大的影響。因此,咱們有必要從新出發,好好認識一下這個東西。mysql

這是一篇短小精悍的文章,仔細閱讀必定能學到很多東西!git

1.切記不要用字符串存儲日期

我記得我在大學的時候就這樣幹過,並且如今不少對數據庫不太瞭解的新手也會這樣幹,可見,這種存儲日期的方式的優勢仍是有的,就是簡單直白,容易上手。程序員

可是,這是不正確的作法,主要會有下面兩個問題:github

  1. 字符串佔用的空間更大!
  2. 字符串存儲的日期比較效率比較低(逐個字符進行比對),沒法用日期相關的 API 進行計算和比較。

2.Datetime 和 Timestamp 之間抉擇

Datetime 和 Timestamp 是 MySQL 提供的兩種比較類似的保存時間的數據類型。他們二者究竟該如何選擇呢?面試

一般咱們都會首選 Timestamp。 下面說一下爲何這樣作!spring

2.1 DateTime 類型沒有時區信息的

DateTime 類型是沒有時區信息的(時區無關) ,DateTime 類型保存的時間都是當前會話所設置的時區對應的時間。這樣就會有什麼問題呢?當你的時區更換以後,好比你的服務器更換地址或者更換客戶端鏈接時區設置的話,就會致使你從數據庫中讀出的時間錯誤。不要小看這個問題,不少系統就是由於這個問題鬧出了不少笑話。sql

Timestamp 和時區有關。Timestamp 類型字段的值會隨着服務器時區的變化而變化,自動換算成相應的時間,說簡單點就是在不一樣時區,查詢到同一個條記錄此字段的值會不同。數據庫

下面實際演示一下!後端

建表 SQL 語句:springboot

CREATE TABLE `time_zone_test` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `date_time` datetime DEFAULT NULL,
  `time_stamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;複製代碼

插入數據:

INSERT INTO time_zone_test(date_time,time_stamp) VALUES(NOW(),NOW());複製代碼

查看數據:

select date_time,time_stamp from time_zone_test;複製代碼

結果:

+---------------------+---------------------+
| date_time           | time_stamp          |
+---------------------+---------------------+
| 2020-01-11 09:53:32 | 2020-01-11 09:53:32 |
+---------------------+---------------------+複製代碼

如今咱們運行

修改當前會話的時區:

set time_zone='+8:00';複製代碼

再次查看數據:

+---------------------+---------------------+
| date_time           | time_stamp          |
+---------------------+---------------------+
| 2020-01-11 09:53:32 | 2020-01-11 17:53:32 |
+---------------------+---------------------+複製代碼

擴展:一些關於 MySQL 時區設置的一個經常使用 sql 命令

# 查看當前會話時區
SELECT @@session.time_zone;
# 設置當前會話時區
SET time_zone = 'Europe/Helsinki';
SET time_zone = "+00:00";
# 數據庫全局時區設置
SELECT @@global.time_zone;
# 設置全局時區
SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';複製代碼

2.2 DateTime 類型耗費空間更大

Timestamp 只須要使用 4 個字節的存儲空間,可是 DateTime 須要耗費 8 個字節的存儲空間。可是,這樣一樣形成了一個問題,Timestamp 表示的時間範圍更小。

  • DateTime :1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
  • Timestamp: 1970-01-01 00:00:01 ~ 2037-12-31 23:59:59

Timestamp 在不一樣版本的 MySQL 中有細微差異。

3 再看 MySQL 日期類型存儲空間

下圖是 MySQL 5.6 版本中日期類型所佔的存儲空間:

能夠看出 5.6.4 以後的 MySQL 多出了一個須要 0 ~ 3 字節的小數位。Datatime 和 Timestamp 會有幾種不一樣的存儲空間佔用。

爲了方便,本文咱們仍是默認 Timestamp 只須要使用 4 個字節的存儲空間,可是 DateTime 須要耗費 8 個字節的存儲空間。

4.數值型時間戳是更好的選擇嗎?

不少時候,咱們也會使用 int 或者 bigint 類型的數值也就是時間戳來表示時間。

這種存儲方式的具備 Timestamp 類型的所具備一些優勢,而且使用它的進行日期排序以及對比等操做的效率會更高,跨系統也很方便,畢竟只是存放的數值。缺點也很明顯,就是數據的可讀性太差了,你沒法直觀的看到具體時間。

時間戳的定義以下:

時間戳的定義是從一個基準時間開始算起,這個基準時間是「1970-1-1 00:00:00 +0:00」,從這個時間開始,用整數表示,以秒計時,隨着時間的流逝這個時間整數不斷增長。這樣一來,我只須要一個數值,就能夠完美地表示時間了,並且這個數值是一個絕對數值,即不管的身處地球的任何角落,這個表示時間的時間戳,都是同樣的,生成的數值都是同樣的,而且沒有時區的概念,因此在系統的中時間的傳輸中,都不須要進行額外的轉換了,只有在顯示給用戶的時候,才轉換爲字符串格式的本地時間。

數據庫中實際操做:

mysql> select UNIX_TIMESTAMP('2020-01-11 09:53:32');
+---------------------------------------+
| UNIX_TIMESTAMP('2020-01-11 09:53:32') |
+---------------------------------------+
|                            1578707612 |
+---------------------------------------+
1 row in set (0.00 sec)

mysql> select FROM_UNIXTIME(1578707612);
+---------------------------+
| FROM_UNIXTIME(1578707612) |
+---------------------------+
| 2020-01-11 09:53:32       |
+---------------------------+
1 row in set (0.01 sec)複製代碼

5.總結

MySQL 中時間到底怎麼存儲纔好?Datetime?Timestamp? 數值保存的時間戳?

好像並無一個銀彈,不少程序員會以爲數值型時間戳是真的好,效率又高還各類兼容,可是不少人又以爲它表現的不夠直觀。這裏插一嘴,《高性能 MySQL 》這本神書的做者就是推薦 Timestamp,緣由是數值表示時間不夠直觀。下面是原文:

每種方式都有各自的優點,根據實際場景纔是王道。下面再對這三種方式作一個簡單的對比,以供你們實際開發中選擇正確的存放時間的數據類型:

若是還有什麼問題歡迎給我留言!若是文章有什麼問題的話,也勞煩指出,Guide 哥感激涕零!

後面的文章我會介紹:

  • [ ] Java8 對日期的支持以及爲啥不能用 SimpleDateFormat。
  • [ ] SpringBoot 中如何實際使用(JPA 爲例)

開源項目推薦

做者的其餘開源項目推薦:

  1. JavaGuide:【Java學習+面試指南】 一份涵蓋大部分Java程序員所須要掌握的核心知識。
  2. springboot-guide : 適合新手入門以及有經驗的開發人員查閱的 Spring Boot 教程(業餘時間維護中,歡迎一塊兒維護)。
  3. programmer-advancement : 我以爲技術人員應該有的一些好習慣!
  4. spring-security-jwt-guide :從零入門 !Spring Security With JWT(含權限驗證)後端部分代碼。

公衆號

相關文章
相關標籤/搜索