作者:秦福朗
,didi~爱可生 DBA 团队成员,负责项目日常问题处理及公司平台问题排查。热爱互联网,会摄影、懂厨艺,不会厨艺的 DBA 不是好司机,didi~
本文来源:原创投稿
背景
概念概述
1. TIMESTAMP 和 DATETIME
TIMESTAMP 是一个时间戳,范围是'1970-01-01 00:00:01.000000'UTC 到'2038-01-19 03:14:07.999999'UTC 。 DATETIME 是日期和时间的组合,范围是'1000-01-01 00:00:00.000000'到 '
9999-12-31 23:59:59.999999' 。
TIMESTAMP 和 DATETIME 列都可以自动初始化并且可以更新为当前的日期和时间,列还可以将当前的时间戳指定为默认值、自动更新的值或者两个同时使用都可以。
2. explicit_defaults_for_timestamp
看场景

业务报错“Column ‘create_time’ cannot be null”,该列不能插入 null 值,查看一下表结构:
#只展示部分时间相关列`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
现场进行参数关闭,改为 OFF ,测试插入正常。那么参数值具体为何能操纵 TIMESTAMP 列的默认值和 null 值呢?继续测试分析。
测试分析
没有明确使用 NULL 属性声明的 TIMESTAMP 列会自动使用 NOT NULL 属性声明。给这样的列分配一个 NULL 的值是允许的,并将该列设置为 current timestamp 。 表中的第一个 TIMESTAMP 列,如果没有明确地用 NULL 属性,DEFAULT 属性或 ON UPDATE 属性声明,将自动用 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 属性声明。 在第一个列之后的 TIMESTAMP 列,如果没有明确地用 NULL 属性或明确的 DEFAULT 属性来声明,就会自动声明为 DEFAULT '0000-00-00 00:00:00' 。对于插入的行,如果没有为该列指定明确的值,那么该列将被分配为'0000-00-00 00:00:00' ,并且不会发生警告。根据是否启用了严格的 SQL mode 或包含 NO_ZERO_DATE 的 SQL mode ,默认值'0000-00-00 00:00:00'可能是不被允许的。
不能实现给 TIMESTAMP 列插入一个 NULL 的值,然后自动设置为当前的时间戳。想要插入当前的时间戳,需要将该列设置为 CURRENT_TIMESTAMP 或一个同义词,比如 NOW() 。 没有明确地用 NOT NULL 属性声明的 TIMESTAMP 列会自动用 NULL 属性声明,并允许 NULL 值。给这样的列插入一个 NULL 值,会把它设置为 NULL 值,而不是当前的时间戳。 用 NOT NULL 属性声明的 TIMESTAMP 列不允许NULL值。对于列指定插入 NULL ,如果启用严格的 SQL mode ,其结果是单行插入报错,或者在禁用严格的 SQL mode 下,多行插入的结果是'0000-00-00 00:00:00' 。在任何情况下,给该列赋值为 NULL 都不会将其设置为当前的时间戳。 用 NOT NULL 属性明确声明的 TIMESTAMP 列,如果没有明确的 DEFAULT 属性,将被视为没有默认值。对于插入的行,如果没有为这样的列指定明确的值,其结果取决于 SQL mode 。如果启用了严格的 SQL mode ,会报错。如果没有启用严格的 SQL mode ,该列则被声明为隐含的默认值 "0000-00-00 00:00:00" ,并发出 warning 。这与 MySQL 处理其他时间类型(如 DATETIME )的方式相似。
2. 做个测试就可以看出来:
(1)explicit_defaults_for_timestamp=OFF :
mysql> show variables like "%explicit_defaults_for_timestamp%";+---------------------------------+-------+| Variable_name | Value |+---------------------------------+-------+| explicit_defaults_for_timestamp | OFF |+---------------------------------+-------+1 row in set (0.00 sec)
创建一个带有 timestamp 列的表:
mysql> create table time_off(id int,time timestamp);Query OK, 0 rows affected (0.02 sec)mysql> show create table time_off;+----------+------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------+| Table | Create Table |+----------+------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------+| time_off | CREATE TABLE `time_off` ( `id` int(11) DEFAULT NULL, `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |+----------+------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------+1 row in set (0.00 sec)
向该表插入NULL值试试看:
mysql> insert into time_off values (1,null);Query OK, 1 row affected (0.00 sec) mysql> select * from time_off;+------+---------------------+| id | time |+------+---------------------+| 1 | 2021-10-12 01:05:28 |+------+---------------------+1 row in set (0.00 sec) mysql> update time_off set id=2 where id=1;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from time_off;+------+---------------------+| id | time |+------+---------------------+| 2 | 2021-10-12 01:06:30 |+------+---------------------+1 row in set (0.00 sec)
(2)explicit_defaults_for_timestamp=ON :
mysql> show variables like "%explicit_defaults_for_timestamp%";+---------------------------------+-------+| Variable_name | Value |+---------------------------------+-------+| explicit_defaults_for_timestamp | ON |+---------------------------------+-------+1 row in set (0.01 sec)
创建一个带有 timestamp 列的表:
mysql> create table time_on(id int,time timestamp);Query OK, 0 rows affected (0.01 sec) mysql> show create table time_on;+---------+--------------------------------------------------------------------------------------------------------------------------------------------------------+| Table | Create Table |+---------+--------------------------------------------------------------------------------------------------------------------------------------------------------+| time_on | CREATE TABLE `time_on` ( `id` int(11) DEFAULT NULL, `time` timestamp NULL DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |+---------+--------------------------------------------------------------------------------------------------------------------------------------------------------+1 row in set (0.00 sec)
可以看到此时 timestamp 列会有默认属性‘NULL DEFAULT NULL’。向该表插入 NULL 值试试看:
mysql> insert into time_on values (1,null);Query OK, 1 row affected (0.00 sec) mysql> select * from time_on;+------+------+| id | time |+------+------+| 1 | NULL |+------+------+1 row in set (0.00 sec)
那么在该参数下,向参数值为 OFF 时创建的表 time_off 里插入 null 值会有什么情况呢:
mysql> insert into time_off values (3,null);ERROR 1048 (23000): Column 'time' cannot be null
结语
关于该参数,实际上是规范了 MySQL 时间相关的操作,使之更加严格,是有助于MySQL的规范化使用的,所以 MySQL 后续也废弃掉该参数。
文章推荐:
技术分享 | MariaDB 迁移到 MySQL 的部分注意事项
社区近期动态

点一下“阅读原文”了解更多资讯文章转载自爱可生开源社区,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。





