為什麼 MySQL 5.7 時間戳不為空需要預設值?
當我嘗試創建具有非空時間戳的表時,它需要我為其添加預設時間戳或使用隱式 default。但我不確定為什麼這是必要的。
看看https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=c615bce0cd1009b0c597593e73fdd794,
下面的 SQL
create table t3 ( id int not null, d1 timestamp not null, num double not null) engine=innodb;
將轉變為
CREATE TABLE `t3` ( `id` int(11) NOT NULL, `d1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `num` double NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1
使用此類工具時,我們可以清楚地看到 int 和 double 不會自動為其生成預設值,但 timestamp 會。時間戳需要預設值而另一個不需要的原因是什麼?
就個人而言,我希望沒有預設值,並且當最終使用者將數據插入沒有
d1
時間戳的行時,將引發異常並且該行將無法注入表中。但顯然這似乎不是 MySQL 正在採取的想法。
在explicit_defaults_for_timestamp上特別提到了
如果 explicit_defaults_for_timestamp 被禁用,伺服器將啟用非標準行為並按如下方式處理 TIMESTAMP 列:
如果未使用 NULL 屬性或顯式 DEFAULT 或 ON UPDATE 屬性顯式聲明表中的第一個 TIMESTAMP 列,則會自動使用 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 屬性聲明。
此行為僅在顯式_預設值_for_timestamp 被禁用時發生在第一個 TIMESTAMP 列。
mysql> select version(); +-----------------------------+ | version() | +-----------------------------+ | 5.7.16-0ubuntu0.16.04.1-log | +-----------------------------+ mysql> show variables like "%explicit_defaults_for_timestamp%"; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | explicit_defaults_for_timestamp | OFF | +---------------------------------+-------+ mysql> create table t3 ( -> id int not null, -> d1 timestamp not null, -> d2 timestamp not null, -> num double not null) -> engine=innodb; Query OK, 0 rows affected (0.31 sec) mysql> show create table t3; CREATE TABLE `t3` ( `id` int(11) NOT NULL, `d1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `d2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `num` double NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1
根據問題
使用此類工具時,我們可以清楚地看到 int 和 double 不會自動為其生成預設值,但 timestamp 會。時間戳需要預設值而另一個不需要的原因是什麼?
MySQL 處理時間戳的方式與其他數據類型不同。
就個人而言,我希望沒有預設值,並且當最終使用者將數據插入沒有 d1 時間戳的行時
這可以通過啟用
explicit_defaults_for_timestamp
mysql> set session explicit_defaults_for_timestamp = 1; Query OK, 0 rows affected (0.00 sec) mysql> show session variables like "%explicit_defaults_for_timestamp%"; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | explicit_defaults_for_timestamp | ON | +---------------------------------+-------+ 1 row in set (0.00 sec) mysql> drop table t3; Query OK, 0 rows affected (0.09 sec) mysql> create table t3 ( -> id int not null, -> d1 timestamp not null, -> num double not null) -> engine=innodb; Query OK, 0 rows affected (0.18 sec) mysql> show create table t3; CREATE TABLE `t3` ( `id` int(11) NOT NULL, `d1` timestamp NOT NULL, `num` double NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec)
(Ergest 對事情的現狀進行了很好的討論。我將說明原因。)
為什麼?這是一個古老的“功能”。突然刪除該功能會導致遷移問題。
在過去,20 多年前,
DEFAULT
值大多由 MySQL 提供,並沒有明確提供。特別TIMESTAMP
是,根據定義給出DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
,但沒有具體說明。注意:這是唯一
DEFAULT
不是常量的隱式情況。(好吧,AUTO_INCREMENT
是另一個。)後來,當
DEFAULT
允許採用更複雜的語法時,設計人員需要決定如何處理從舊版本升級的數據庫。這導致了一些笨拙explicit_defaults_for_timestamp
的事情,比如妥協。