mysql?timestamp字段規(guī)范使用詳情
1. 前言
這個世界離不開時間,同樣,數(shù)據(jù)庫中也是如此,表中的每條記錄除了數(shù)據(jù)模型的時間字段(如生日,生產(chǎn)日期,出發(fā)日期等),一般至少還有兩個固定的時間字段:記錄插入時間,記錄更新時間。
然而,看似很簡單時間字段,誰能想到會導(dǎo)致應(yīng)用報錯,引發(fā)血案:

個中緣由,正是接下來要講到的。
2. mysql中的時間字段
因時間字段的一些特性與版本有關(guān),且目前我司統(tǒng)一使用的mysql 5.7版本,因此本文內(nèi)容都基于mysql 5.7。
mysql時間相關(guān)的字段主要有DATE、DATETIME、TIMESTAMP。

其中datatime和timestamp字段都可以包含小數(shù),如datetime(6),字節(jié)長度的可變部分(0-3)由小數(shù)位數(shù)決定:

2.1. 數(shù)據(jù)的存儲方式
DATE:
3個字節(jié)的整型,按照這種方式進(jìn)行壓縮: YYYY×16×32 + MM×32 + DD
DATETIME:
整數(shù)部分5個字節(jié),由以下部分組成

TIMESTAMP:
整數(shù)部分4個字節(jié),存儲從(‘1970-01-01 00:00:00’ UTC)到指定時間的秒數(shù);
timestamp類型是4個字節(jié),最大值是2的31次方減1,也就是2147483647,轉(zhuǎn)換成北京時間就是2038-01-19 11:14:07
2.2. DATETIME和TIMESTMAP的區(qū)別
- 數(shù)據(jù)的存儲方式?jīng)Q定了timestamp的計算和索引效率比datetime更快;
- timestamp存儲的時間范圍比datetime小很多;
- timestamp數(shù)據(jù)顯示時要根據(jù)時區(qū)換算,datetime數(shù)據(jù)顯示時不受時區(qū)影響;
admin@test 04:42:41>show variables like 'time_zone'; +---------------+--------+ | Variable_name | Value | +---------------+--------+ | time_zone | +08:00 | +---------------+--------+ admin@test 04:42:42>create table t1(dt datetime,ts timestamp); admin@test 04:43:07>insert into t1 values(now(),now()); admin@test 04:43:17>select * from t1; +---------------------+---------------------+ | dt | ts | +---------------------+---------------------+ | 2021-03-27 16:43:17 | 2021-03-27 16:43:17 | +---------------------+---------------------+ admin@test 04:43:50>set time_zone='+09:00'; admin@test 04:44:00>select * from t1; +---------------------+---------------------+ | dt | ts | +---------------------+---------------------+ | 2021-03-27 16:43:17 | 2021-03-27 17:43:17 | +---------------------+---------------------+ admin@test 04:44:07>
timestamp在處理默認(rèn)值和null值時的行為時受mysql參數(shù)explicit_defaults_for_timestamp控制,datatime不受影響。
3. timestamp字段處理默認(rèn)值和null值時的行為
3.1. 參數(shù)禁用
當(dāng)禁用該值時(explicit_defaults_for_timestamp=0),mysql啟用timestamp字段的特有行為(和數(shù)字、字符串等類型的表現(xiàn)不同),
具體特性如下:
- timestamp字段默認(rèn)設(shè)置為not null
- 表中的第一個timestamp字段插入時默認(rèn)設(shè)置當(dāng)前時間,更新時,默認(rèn)更新為當(dāng)前時間,即默認(rèn)設(shè)置為以下特性:NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
- 表中的第二個timestamp字段默認(rèn)為'0000-00-00 00:00:00'
- 顯式向timestamp字段插入null值時,不會報錯,且都設(shè)置為當(dāng)前時間;
- 對datetime字段的行為無影響。
admin@test 05:49:00>create table t2(id int auto_increment, name varchar(100), dt1 datetime, ts1 timestamp, ts2 timestamp, primary key(id)); admin@test 05:49:48>show create table t2; ±------±--------------------------------------------------------------------------+ | Table | Create Table | ±------±--------------------------------------------------------------------------+ | t2 | CREATE TABLE t2 ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(100) DEFAULT NULL, dt1 datetime DEFAULT NULL, ts1 timestamp NULL DEFAULT NULL, ts2 timestamp NULL DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 | ±------±--------------------------------------------------------------------------+ 1 row in set (0.00 sec) admin@test 05:50:20>insert into t2(name) values(‘a(chǎn)1'); Query OK, 1 row affected (0.00 sec) admin@test 05:51:07>select * from t2; ±—±-----±-----±-----±-----+ | id | name | dt1 | ts1 | ts2 | ±—±-----±-----±-----±-----+ | 1 | a1 | NULL | NULL | NULL | ±—±-----±-----±-----±-----+ 1 row in set (0.00 sec) ##注:插入記錄時,默認(rèn)為null admin@test 05:54:20>update t2 set name=‘a(chǎn)a1' where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 admin@test 05:54:31>select * from t2; ±—±-----±-----±-----±-----+ | id | name | dt1 | ts1 | ts2 | ±—±-----±-----±-----±-----+ | 1 | aa1 | NULL | NULL | NULL | ±—±-----±-----±-----±-----+ 1 row in set (0.00 sec) ##注:更新記錄時,默認(rèn)為null admin@test 05:58:10>create table t3(id int auto_increment,name varchar(100),ts1 timestamp not null default current_timestamp,primary key(id)); admin@test 05:58:18>insert into t3(name) values(‘a(chǎn)1'); Query OK, 1 row affected (0.00 sec) admin@test 05:58:22>select * from t3; ±—±-----±--------------------+ | id | name | ts1 | ±—±-----±--------------------+ | 1 | a1 | 2021-03-23 17:58:22 | ±—±-----±--------------------+ 1 row in set (0.00 sec) ##注:創(chuàng)建表手動設(shè)置not null default current_timestamp,插入記錄不含timestamp字段時,默認(rèn)為當(dāng)前時間 admin@test 05:58:25>insert into t3(name,ts1) values(‘a(chǎn)1',null); ERROR 1048 (23000): Column ‘ts1' cannot be null ##注:timestamp字段顯式插入null時,報錯Column ‘ts1' cannot be null admin@test 05:59:11>create table t4(id int auto_increment,name varchar(100),ts1 timestamp not null ,primary key(id)); Query OK, 0 rows affected (0.04 sec) admin@test 05:59:44>insert into t4(name) values(‘a(chǎn)1'); ERROR 1364 (HY000): Field ‘ts1' doesn't have a default value admin@test 05:59:49> ##注:創(chuàng)建表手動設(shè)置not null,插入記錄不含timestamp字段時,報錯Field doesn't have a default value admin@test 05:59:50>insert into t4(name,ts1) values(‘a(chǎn)1',null); ERROR 1048 (23000): Column ‘ts1' cannot be null admin@test 05:59:57> ##注:timestamp字段顯式插入null時,報錯Column ‘ts1' cannot be null
3.2. 參數(shù)啟用
當(dāng)啟用該值時(explicit_defaults_for_timestamp=1),mysql禁用timestamp字段的特有行為,具體表現(xiàn)和數(shù)字、字符串類型一樣。
- timestamp字段默認(rèn)屬性是“NULL DEFAULT NULL”;
- timestamp字段手動設(shè)置了not null和default后,顯式插入null值會報錯:Column cannot be null;
- timestamp字段同時設(shè)置了not null但未設(shè)置default后,顯式插入null值會報錯:Column cannot be null,插入記錄不含timestamp字段時會報錯Field doesn’t have a default value;
- 對datetime字段的行為無影響。
admin@test 05:49:00>create table t2(id int auto_increment, name varchar(100), dt1 datetime, ts1 timestamp, ts2 timestamp, primary key(id));
admin@test 05:49:48>show create table t2;
+-------+---------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------+
| t2 | CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`dt1` datetime DEFAULT NULL,
`ts1` timestamp NULL DEFAULT NULL,
`ts2` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+---------------------------------------------------------------------------+
1 row in set (0.00 sec)
admin@test 05:50:20>insert into t2(name) values(‘a(chǎn)1');
Query OK, 1 row affected (0.00 sec)
admin@test 05:51:07>select * from t2;
±—±-----±-----±-----±-----+
| id | name | dt1 | ts1 | ts2 |
±—±-----±-----±-----±-----+
| 1 | a1 | NULL | NULL | NULL |
±—±-----±-----±-----±-----+
1 row in set (0.00 sec)
## 注:插入記錄時,默認(rèn)為null
admin@test 05:54:20>update t2 set name=‘a(chǎn)a1' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
admin@test 05:54:31>select * from t2;
±—±-----±-----±-----±-----+
| id | name | dt1 | ts1 | ts2 |
±—±-----±-----±-----±-----+
| 1 | aa1 | NULL | NULL | NULL |
±—±-----±-----±-----±-----+
1 row in set (0.00 sec)
## 注:更新記錄時,默認(rèn)為null
admin@test 05:58:10>create table t3(id int auto_increment,name varchar(100),ts1 timestamp not null default current_timestamp,primary key(id));
admin@test 05:58:18>insert into t3(name) values(‘a(chǎn)1');
Query OK, 1 row affected (0.00 sec)
admin@test 05:58:22>select * from t3;
±—±-----±--------------------+
| id | name | ts1 |
±—±-----±--------------------+
| 1 | a1 | 2021-03-23 17:58:22 |
±—±-----±--------------------+
1 row in set (0.00 sec)
##注:創(chuàng)建表手動設(shè)置not null default current_timestamp,插入記錄不含timestamp字段時,默認(rèn)為當(dāng)前時間
admin@test 05:58:25>insert into t3(name,ts1) values(‘a(chǎn)1',null);
ERROR 1048 (23000): Column ‘ts1' cannot be null
##注:timestamp字段顯式插入null時,報錯Column ‘ts1' cannot be null
admin@test 05:59:11>create table t4(id int auto_increment,name varchar(100),ts1 timestamp not null ,primary key(id));
Query OK, 0 rows affected (0.04 sec)
admin@test 05:59:44>insert into t4(name) values(‘a(chǎn)1');
ERROR 1364 (HY000): Field ‘ts1' doesn't have a default value
admin@test 05:59:49>
##注:創(chuàng)建表手動設(shè)置not null,插入記錄不含timestamp字段時,報錯Field doesn't have a default value
admin@test 05:59:50>insert into t4(name,ts1) values(‘a(chǎn)1',null);
ERROR 1048 (23000): Column ‘ts1' cannot be null
admin@test 05:59:57>
##注:timestamp字段顯式插入null時,報錯Column ‘ts1' cannot be null4. 總結(jié)
啟用該參數(shù)(explicit_defaults_for_timestamp=1)
timestamp字段在null、default屬性的表現(xiàn)和其他普通字段表現(xiàn)類似:
- 如果沒有顯式設(shè)置default值,該值的維護(hù)完全需要應(yīng)用程序顯式插入和更新;
- 如果設(shè)置了not null,那么一定不能顯式插入null值,否則應(yīng)用會報錯。
禁用該參數(shù)(explicit_defaults_for_timestamp=0)
timestamp字段在null、default屬性的表現(xiàn)和其他普通字段表現(xiàn)有明顯差異:
- 默認(rèn)會設(shè)置NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
- 顯式插入null值,默認(rèn)為當(dāng)前時間,應(yīng)用不會報錯。
案例發(fā)生的場景:
公司所有集群已經(jīng)統(tǒng)一啟用該參數(shù);
某集群過去某個時間因為研發(fā)的要求,將該參數(shù)禁用,但是這次集群切換后的新服務(wù)器采用了統(tǒng)一的參數(shù)模板,啟用了參數(shù);
應(yīng)用程序顯式向timestamp字段插入null值,且該字段已經(jīng)設(shè)置了not null,在禁用該參數(shù)的集群不會報錯,但是切換到啟用了該參數(shù)的集群時,就報column cannot be null.
統(tǒng)一規(guī)范:
個別集群禁用該參數(shù)導(dǎo)致公司所有的mysql集群參數(shù)不統(tǒng)一,可能帶來應(yīng)用報錯的后果,因此建議:
- 統(tǒng)一公司所有集群的參數(shù)explicit_defaults_for_timestamp=1;
- 用timestamp字段時設(shè)置default和not null屬性;
- 應(yīng)用程序不要顯式插入null值。
到此這篇關(guān)于mysql timestamp字段規(guī)范使用詳情的文章就介紹到這了,更多相關(guān)mysql timestamp字段 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MYSQL?數(shù)據(jù)庫時間字段?INT,TIMESTAMP,DATETIME?性能效率的比較介紹
- 淺談mysql的timestamp存在的時區(qū)問題
- MySQL中CURRENT_TIMESTAMP時間戳的使用詳解
- 詳解MySQL中timestamp和datetime時區(qū)問題導(dǎo)致做DTS遇到的坑
- mysql timestamp比較查詢遇到的坑及解決
- MySQL 中 datetime 和 timestamp 的區(qū)別與選擇
- MySQL如何修改字段的默認(rèn)值和空值
- MySQL為JSON字段創(chuàng)建索引方式(Multi-Valued?Indexes?多值索引)
相關(guān)文章
Linux虛擬機(jī)下mysql 5.7安裝配置方法圖文教程
這篇文章主要為大家詳細(xì)介紹了Linux虛擬機(jī)下mysql 5.7安裝配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01
windows下mysql 8.0.13 解壓版安裝圖文教程
這篇文章主要為大家詳細(xì)介紹了windows下mysql 8.0.13 解壓版安裝圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-02-02
MySQL數(shù)據(jù)時區(qū)問題以及datetime和timestamp類型存儲的差異
這篇文章主要介紹了MySQL數(shù)據(jù)時區(qū)問題以及datetime和timestamp類型存儲的差異,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
MySQL中g(shù)roup_concat函數(shù)深入理解
本文通過實(shí)例介紹了MySQL中的group_concat函數(shù)的使用方法,需要的朋友可以適當(dāng)參考下2012-11-11
MySQL一個語句查出各種整形占用字節(jié)數(shù)及最大最小值的實(shí)例
下面小編就為大家?guī)硪黄狹ySQL一個語句查出各種整形占用字節(jié)數(shù)及最大最小值的實(shí)例。2017-03-03
如何在Windows中運(yùn)行多個MySQL實(shí)例詳解
這篇文章主要給大家介紹了關(guān)于如何在Windows中運(yùn)行多個MySQL實(shí)例的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
mysql自動停止 Plugin FEDERATED is disabled 的完美解決方法
今天在配置服務(wù)器的時候,發(fā)現(xiàn)mysql的一個錯誤提示在 本地計算機(jī) 無法啟動 MySQL 服務(wù)。錯誤 1067: 進(jìn)程意外終止,其實(shí)原因很多這個不是導(dǎo)致進(jìn)程意外終止的最終原因,但可以解決2016-04-04
實(shí)現(xiàn)MySQL與elasticsearch的數(shù)據(jù)同步的代碼示例
MySQL 自身簡單、高效、可靠,是又拍云內(nèi)部使用最廣泛的數(shù)據(jù)庫,但是當(dāng)數(shù)據(jù)量達(dá)到一定程度的時候,對整個 MySQL 的操作會變得非常遲緩,這個時候我們就需要MySQL與elasticsearch數(shù)據(jù)同步,接下來就給大家介紹如何實(shí)現(xiàn)數(shù)據(jù)同步2023-07-07

