Mysql

為什麼 MySQL 5.7 時間戳不為空需要預設值?

  • July 28, 2022

當我嘗試創建具有非空時間戳的表時,它需要我為其添加預設時間戳或使用隱式 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的事情,比如妥協。

引用自:https://dba.stackexchange.com/questions/314898