傻傻分不清的 DATE、DATETIME 和 TIMESTAMP ( 中 )

撸了今年阿里、腾讯和美团的面试,我有一个重要发现…….

出处:https://www.twle.cn


不使用 date 、datetime 和 timestamp 三个类型的另外一个非重要原因,是一直记不住如何设置 datetime 和 timestamp 的默认值。

一般情况下,我在创建表结构的时候都会添加 created_at 和 updated_at 作为记录创建时间和记录最近更新时间,这两个时间都很好理解,如果使用 datetime 或 timestamp 则可以设置一些约束在 insert 数据和 update 数据时自动填充其值。

但是,我一贯的用法,就是把它们定义为一个整数类型 ( int ),然后使用应用程序级别的时间戳填充,其实,这是很简单愚蠢的。

MySQL 可以帮我们做这些事情,前提就是使用 datetime 和 timestamp 两个类型。

timestamp 和 datetime 列可以自动初始化并更新为当前日期和时间 ( 即当前时间戳 ) 。

对于 MySQL 表中的任何 timestamp 和 datetime 列,我们可以将设置当前时间戳为默认值,自动更新值或两者皆有:

  1. 如果将某个列设置为插入时自动初始化为当前时间戳,那么就可以不用为这些列指定任何值。

  2. 当行中任何其他列的值发生变更时,设置了自动更新的列将自动更新为当前时间戳。

当然了,这里有一个要点,如果 update 时任何其它列的数据并没有发生变更,那么自动更新列保持不变。

如果要更新自动更新的列,即使其他列未更改,则需要显式设置值为应具有的值,例如使用 CURRENT_TIMESTAMP()

如果要防止在其他列更改时更新自动更新列,则需要显式的设置自动更新列的值为当前值

除了以上这些规则,如果禁用 ( disabled ) 了 explicit_defaults_for_timestamp 系统变量,则可以通过为其指定 NULL 值来初始化或更新任何 timestamp(但不是 datetime )列到当前日期和时间,除非已使用 NULL 属性定义允许 NULL 值

正如上一章节中所提到的那样,要指定自动属性,可以在创建表时在列定义中使用 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 两个约束,约束的顺序无关紧要。

如果这两个约束同时存在于某个列定义中,那么任何一个都可能先执行。

CURRENT_TIMESTAMP 可以使用任何同义词代替,任何 CURRENT_TIMESTAMP 的任何同义词与 CURRENT_TIMESTAMP 具有相同的含义,例如 CURRENT_TIMESTAMP()NOW()LOCALTIMELOCALTIME()LOCALTIMESTAMP 和 LOCALTIMESTAMP() 。

当在 datetime 和 timestamp 列上使用了 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 约束时,其实还是可以添加 DEFAULT 约束的,default 约束用于指定常量 (非自动 ) 默认值;例如 DEFAULT 0 或 DEFAULT '2018-09-14 00:00:00'

下面的示例中可能会使用到 default 0 ,这是一个默认值,但可以产生警告或错误,具体取决于是否启用了严格的 SQL 模式或 NO_ZERO_DATE SQL 模式。

timestamp 和 datetime 列可以同时指定默认值和自动更新值为当前时间戳,也可以值指定其中一个,或者两个都不指定。不同的列可以具有不同的自动属性组合。下面的规则则描述了一些可能的使用场景

  1. 同时指定 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP,那么该列会自动设置当前时间为默认值,并自动更新为当前时间戳
 CREATE TABLE t1 (
  ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
  1. 使用了 default 约束,当没有使用 ON UPDATE CURRENT_TIMESTAMP 约束时,该列会自动使用给定的默认值,但不会自动更新为当前时间戳

而默认的值取决于 default 子句是指定 CURRENT_TIMESTAMP 还是常量值。

如果使用 CURRENT_TIMESTAMP,默认值是当前时间戳

 CREATE TABLE t1 (
  ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  dt DATETIME DEFAULT CURRENT_TIMESTAMP
);

如果使用了常量值,默认值是则为给定值,在这种情况下,该列根本没有自动属性

 CREATE TABLE t1 (
  ts TIMESTAMP DEFAULT 0,
  dt DATETIME DEFAULT 0
);
  1. 如果使用了 ON UPDATE CURRENT_TIMESTAMP 约束和常量 default 约束,该列将自动更新为当前时间戳并具有给定的常量默认值
 CREATE TABLE t1 (
  ts TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP,
  dt DATETIME DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP
);
  1. 如果使用了 ON UPDATE CURRENT_TIMESTAMP 约束当没有使用 default 约束,该列将自动更新为当前时间戳,且不会使用当前时间戳作为其默认值

这种情况下的默认值取决于所使用的类型。

timestamp 类型的默认值为 0,除非使用了 NULL 约束,那么默认值就是 NULL

 CREATE TABLE t1 (
  ts1 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  -- default 0
  ts2 TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP -- default NULL
);

datetime 类型的默认值为 NULL ,除非使用 NOT NULL 约束,那么默认值就是 0

 CREATE TABLE t1 (
  dt1 DATETIME ON UPDATE CURRENT_TIMESTAMP,-- default NULL
  dt2 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP -- default 0
);

需要注意的是,datetime 和 timstamp 默认是么有任何自动属性的,如果需要自动属性需要显式的指明,但有一个例外情况:

「 如果禁用了系统变量 explicit_defaults_for_timestamp ,且没有任何一个 timestamp 类型的列明确的设置了自动属性,那么第一个 timestamp 类型的列会自动设置为 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 」

如果要禁止第一个 timestamp 列自动设置 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 属性,有以下几种方法

  • 启用 explicit_defaults_for_timestamp 系统变量。

在这种情况下,可以为 timestamp 列设置自动初始化和自动更新的 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP,但需要明确指明,否则任何 timetamp 都不会获得这些自动属性

  • 或者,保持禁用 explicit_defaults_for_timestamp ,但通过以下方法来改变:

  • 使用 default 约束为 timestamp 指定一个默认的常量值。

  • 使用 null 约束。

    但因为使用了 NULL 约束,导致列允许 NULL 值,也就意味着无法通过将列设置为 NULL 来分配当前时间戳。

    使用 NULL 约束会将列设置为 NULL,而不是当前时间戳,如果要分配当前时间戳,则需要将列设置为 CURRENT_TIMESTAMP 或同义词,例如NOW()

比如下面这个表结构定义

CREATE TABLE t1 (
 ts1 TIMESTAMP DEFAULT 0,
 ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);
CREATE TABLE t2 (
 ts1 TIMESTAMP NULL,
 ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);
CREATE TABLE t3 (
 ts1 TIMESTAMP NULL DEFAULT 0,
 ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);

这些表 t1、t2、t3 具有以下特征

  • 每个表结构定义中,第一个 TIMESTAMP 列没有设置自动初始化或自动更新。

  • 这些表的不同之处在于 ts1 列如何处理 NULL 值

  • 对于 t1,ts1 为 NOT NULL,并为其赋值为 NULL,这会将其值设置为当前时间戳

  • 对于 t2 和 t3 ,ts1 允许 NULL,并为其赋值 NULL
  • t2 和 t3 在 ts1 的默认值上有所不同。

  • 对于 t2,ts1 被定义为允许 NULL,因此在没有显式 DEFAULT 子句的情况下,缺省值也为 NULL

  • 对于 t3,ts1 允许 NULL 但显式默认值为 0

对于 datetime 和 timestamp 列,无论在任何位置定义了小数位数,则必须在整个列定义中使用相同的值,例如

CREATE TABLE t1 (
 ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
);

但下面这种是不允许的

CREATE TABLE t1 (
 ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(3)
);
赞(0) 打赏

如未加特殊说明,此网站文章均为原创,转载必须注明出处。Java 技术驿站 » 傻傻分不清的 DATE、DATETIME 和 TIMESTAMP ( 中 )
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

关注【Java 技术驿站】公众号,每天早上 8:10 为你推送一篇技术文章

扫描二维码关注我!


关注【Java 技术驿站】公众号 回复 “VIP”,获取 VIP 地址永久关闭弹出窗口

免费获取资源

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏