为什么MySQL 5.7时间戳不为空需要默认值?

CHA*_*ist 3 mysql mysql-5.7

当我尝试创建具有非空时间戳的表时,它要求我向其中添加默认时间戳或使用隐式默认值。但我不确定为什么这是必要的。

看看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;
Run Code Online (Sandbox Code Playgroud)

将转变为

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
Run Code Online (Sandbox Code Playgroud)

使用此类工具时,我们可以清楚地看到 int 和 double 不会自动为其生成默认值,但 timestamp 会自动生成默认值。为什么时间戳需要默认值,而另一个不需要默认值,这背后的原因是什么?

就我个人而言,我希望没有默认值,并且当最终用户将数据插入没有d1时间戳的行时,将引发异常,并且此类行将无法注入到表中。但显然这似乎并不是 MySQL 所采取的想法。

Erg*_*sha 5

在explicit_defaults_for_timestamp上特别提到

如果禁用explicit_defaults_for_timestamp,服务器将启用非标准行为并按如下方式处理TIMESTAMP列:

表中的第一个 TIMESTAMP 列,如果未使用 NULL 属性或显式 DEFAULT 或 ON UPDATE 属性显式声明,则会自动使用 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 属性进行声明。

仅当禁用explicit_defaults_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  
Run Code Online (Sandbox Code Playgroud)

根据问题

使用此类工具时,我们可以清楚地看到 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)
Run Code Online (Sandbox Code Playgroud)