這片博客來詳細分區一下這哥倆!
首先來說明這兩個字符類型:
| DATETIME | 8 | 1000-01-01 00:00:00 ~9999~12-31 23:59:59 | 0000-00-00 00:00:00 |
| TIMESTAMP(包含時區信息) | 4 | 1970-01-01 08:00:01~2038-01-19 11:14:07 | 0000-00-00 00:00:00 |
如上直觀的看到timestamp類型占用了更少的字節,但是timestamp表示的時間卻是有限的。
這兩個值都可以自動初始化並且更新為當前的時間戳,對於表中的任何TIMESTAMP或 DATETIME列,您可以將當前時間戳分配為默認值,自動更新值或兩者:
首先說這兩個類型都可以做的事: 這兩個類型都可以設置默認值,也都可以設置自動更新。下面舉例說明。
create table tb5( t1 datetime default current_timestamp on update current_timestamp, #設置為當前時間戳為默認值,並且自動更新 t2 datetime default current_timestamp, #僅設置當前時間戳為默認值 t3 timestamp default current_timestamp on update current_timestamp, t4 timestamp default current_timestamp,
t5 varchar(10), t6 int auto_increment not null primary key)
當向表中插入一條數據時,t1~t4會插入當前時間戳的默認值!
mysql> insert into tb5(t5) select NULL; Query OK, 1 row affected (0.05 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from tb5; #t1~t4因為是以當前時間戳為默認值的,因此相等。 +---------------------+---------------------+---------------------+---------------------+------+----+ | t1 | t2 | t3 | t4 | t5 | t6 | +---------------------+---------------------+---------------------+---------------------+------+----+ | 2019-01-09 13:58:10 | 2019-01-09 13:58:10 | 2019-01-09 13:58:10 | 2019-01-09 13:58:10 | NULL | 1 | +---------------------+---------------------+---------------------+---------------------+------+----+ 1 row in set (0.00 sec) mysql>
下面我們修改插入的這一行數值,就可以發現不同了!
mysql> update tb5 set t5="a" where t6=1; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from tb5; #看到了什么不一樣的地方。t1和t3的值會自動修改,而t2和t4的值不會的。 +---------------------+---------------------+---------------------+---------------------+------+----+ | t1 | t2 | t3 | t4 | t5 | t6 | +---------------------+---------------------+---------------------+---------------------+------+----+ | 2019-01-09 14:00:49 | 2019-01-09 13:58:10 | 2019-01-09 14:00:49 | 2019-01-09 13:58:10 | a | 1 | +---------------------+---------------------+---------------------+---------------------+------+----+ 1 row in set (0.00 sec)
default current_timestamp: 只是會設置字段值為當前時間戳,不會隨着記錄中其他字段的更新而更新。
on update current_timestamp: 則是表示字段值,會隨着記錄中其他字段值更新而更新為當前時間戳。
官方文檔上說timestamp默認數值為0,datetime默認值為null,但是下面語句卻執行失敗!
create table tb6( t1 datetime on update current_timestamp, t2 datetime not null on update current_timestamp, t3 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, t4 timestamp null on update current_timestamp, t5 varchar(10), t6 int auto_increment not null primary key )
#錯誤提示就是Error Code: 1067. Invalid default value for 't3'
上面的t1和t3只要有對應記錄中字段數值的改變那么t1和t3的值就會更新。如果想不讓他們自動自動更新,除了修改其默認屬性(也就是不添加on update current_timestamp)外,MySQL還有一個變量控制這個行為:explicit_defaults_for_timestamp,其默認值為
mysql> show variables like "%explicit%"; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | explicit_defaults_for_timestamp | OFF | +---------------------------------+-------+ 1 row in set (0.00 sec)
#默認數值為off,把其設置為on即可!
測試一下:
mysql> set global explicit_defaults_for_timestamp="ON"; #設置這個參數值為ON Query OK, 0 rows affected (0.00 sec) mysql> set session explicit_defaults_for_timestamp="ON"; Query OK, 0 rows affected (0.00 sec) mysql> show variables like "%explicit%"; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | explicit_defaults_for_timestamp | ON | +---------------------------------+-------+ 1 row in set (0.01 sec) mysql> insert into tb5(t5) select NULL; #插入數據, Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from tb5; #查看其第二行的數據 +---------------------+---------------------+---------------------+---------------------+------+----+ | t1 | t2 | t3 | t4 | t5 | t6 | +---------------------+---------------------+---------------------+---------------------+------+----+ | 2019-01-09 14:00:49 | 2019-01-09 13:58:10 | 2019-01-09 14:00:49 | 2019-01-09 13:58:10 | a | 1 | | 2019-01-09 14:44:08 | 2019-01-09 14:44:08 | 2019-01-09 14:44:08 | 2019-01-09 14:44:08 | NULL | 2 | +---------------------+---------------------+---------------------+---------------------+------+----+ 2 rows in set (0.00 sec) mysql> update tb5 set t5="b" where t6=2; #更改第二行的字段值 Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from tb5; #可以看到t1和t3的值還是自動更新了 +---------------------+---------------------+---------------------+---------------------+------+----+ | t1 | t2 | t3 | t4 | t5 | t6 | +---------------------+---------------------+---------------------+---------------------+------+----+ | 2019-01-09 14:00:49 | 2019-01-09 13:58:10 | 2019-01-09 14:00:49 | 2019-01-09 13:58:10 | a | 1 | | 2019-01-09 14:44:41 | 2019-01-09 14:44:08 | 2019-01-09 14:44:41 | 2019-01-09 14:44:08 | b | 2 | +---------------------+---------------------+---------------------+---------------------+------+----+ 2 rows in set (0.00 sec)
原因是什么?explicit_defaults_for_timestamp的數值會影響表結構,當表結構已經創建,那么再設置這個數值是不會起作用的。並且在定義的時候不需要顯示指定on update current_timestamp參數。
可以參考這片博客:https://www.cnblogs.com/JiangLe/p/6956865.html
二者的不同
上面提到的都是這兩個類型都可以做的事,下面來說明二者的不同之處。
1:上面已經提到的二者占用的大小不同,datetime占用8個字節,而timestamp占用4個字節。
2:還有就是表示的時間范圍不同。
3:timestamp的時間顯示值依賴於時區;如果在多個時區存儲或訪問數據,timestamp和datetime的行為將很不一樣。timestamp提供的數值和時區有關系,而datetime則是文本表示的日期和時間。
除了特殊的行為,通常也應該盡量使用TIMESTAMP。
如果要存儲比秒更小粒度的日期和時間怎么辦?MySQL目前沒有提供合適的數據類型,但是可以使用自己的存儲格式;可以使用BIGINT類型存儲微妙級別的問題,或者使用DOUBLE存儲秒之后的小數部分。也可以使用mariadb或者percona server。
