【问题标题】:Inserting NULL into MySQL timestamp将 NULL 插入 MySQL 时间戳
【发布时间】:2012-09-11 10:18:26
【问题描述】:

我观察到在 MySQL 时间戳列中插入/更新 NULL 时出现意外行为。

考虑以下陈述。

create table temp(id int, hireDate timestamp default 0);
insert into temp (id) values(1);
insert into temp (id, hireDate) values(2, null);
select * from temp;
id  hireDate
-----------------------------
1   
2   2012-09-19 10:54:10.0

第一次插入(当 SQL 中没有指定 hiredate 时,hireDate 是 null(0),这是预期的。

但是,当在 SQL 中传递显式 null 时,会插入当前日期时间,这是意外的。为什么会这样?

注意:Hibernate 使用第二种类型的插入,因此它成为一个问题。如何将 null 插入时间戳列?

【问题讨论】:

  • 什么是休眠?这是 MySQL 的默认行为。每次更新行时,时间戳字段也会自动更新
  • 默认 0 是关键。没有它,它仍然是 NULL,而不是 CURRENT_TIMESTAMP

标签: mysql sql database hibernate


【解决方案1】:

如果您想在表的hireDate 列中插入 NULL,那么您必须提供 null

INSERT INTO temp (id, hireDate) VALUES(3, null);

因为hireDateDatatypetimestamp,所以在创建列的时候应该定义为null

【讨论】:

  • 这不会插入null,而是插入带有警告的0000-00-00 00:00:00,就像为时间戳提供任何其他无效值一样。
【解决方案2】:

http://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html

此外,您可以将任何 TIMESTAMP 列初始化或更新为当前日期和时间,方法是为其分配 NULL 值,除非它已使用 NULL 属性定义以允许 NULL 值。

为了使 TIMESTAMP 可以为空,请使用 NULL 属性创建它,或者更改表并添加 NULL 属性。在 create 语句中,它类似于。

CREATE TABLE t1 (tsvalue TIMESTAMP NULL, ... );

NULL 值插入具有 NULL 属性集的 TIMESTAMP 字段将导致该字段为设置为 NULL 而不是 NOW()。

【讨论】:

  • 什么是“Null”属性?
  • 具有 NULL 属性的列允许 NULL 值。 NULL 表示值不存在。例如,表 people 具有列 name 和 job。彼得作为程序员工作,因此名称价值将是彼得,工作价值将是程序员。但是贾斯汀失业了,所以名字价值将是贾斯汀,但工作价值将为 NULL,因为他没有工作
【解决方案3】:

您需要更改hireDate 列的默认值。默认值应为空

这个

create table temp(id int, hireDate timestamp default 0);

应该是这样的:

create table temp(id int, hireDate timestamp null);

【讨论】:

  • hireDate timestamp default null 是语法错误。 hireDate timestamp null 工作。
【解决方案4】:

您可以在 MySQL 时间戳中插入和更新 NULL。

创建表:

create table penguins(id int primary key auto_increment, the_time timestamp NULL);

插入一些行:

insert into penguins(the_time) values (now());
insert into penguins(the_time) values (null);
insert into penguins(the_time) values (0);
insert into penguins(the_time) values ('1999-10-10 01:02:03');

哪些打印:

select * from penguins

1   2015-01-23 15:40:36
2   
3   0000-00-00 00:00:00
4   1999-10-10 01:02:03

第 2 行中名为 the_time 且数据类型为 timestamp 的列的值为 NULL。

【讨论】:

    【解决方案5】:

    切勿将任何应用程序值存储到 MySQL 时间戳类型列中。 仅将时间戳类型用于数据库服务器端动态时间戳(请参阅 DEFAULT 和 ON UPDATE 列属性)。 通过调用列“mysql_row_created_at”和“mysql_row_updated_at”来明确说明。

    请注意,MySQL 将其时间戳类型物理存储为数字 UNIX-epoch-delta,因此它具有 UTC 的隐式时区,这使其不受会话(AKA 连接)级别的时区更改的影响。

    远离“日期时间”类型,在存储任何具有已知时区的值时更是如此。 'datetime' 类型很像一串压缩数字。没有存储时区详细信息。

    通常可以使用“日期”类型。请注意,尽管在某些情况下,它将被解释为(活动时区的)午夜的日期时间,这将导致您应该避免的所有与“日期时间”相关的混淆。

    对于任何应用程序端的日期时间值,使用“int unsigned”、“bigint”(有符号)、“double”(有符号)或小数(N,P)来简单地存储 UNIX-纪元三角洲。 如果不是秒,请确保在列名后缀中显示分辨率。

    例子:

    `mysql_row_created_at` TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
    `mysql_row_updated_at` TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    `epoch` int unsigned NOT NULL,
    `epoch_ms` bigint NOT NULL,
    `epoch_us` bigint NOT NULL,
    `epoch` double NOT NULL,
    `epoch6` decimal(16,6),
    

    尽可能多地处理数据库。所以只能在应用程序端进行任何转换,而不是在数据库端。

    很高兴知道:

    SELECT @@GLOBAL.TIME_ZONE
    , @@SESSION.TIME_ZONE
    , @@SESSION.TIMESTAMP
    , UNIX_TIMESTAMP(NOW(6))
    ;
    

    【讨论】:

      【解决方案6】:

      从旧的 mysql 5.6.44-86.0 升级到 aurora mysql 5.7.12 时,我遇到了类似的行为。该代码将 NULL 作为时间戳插入并期望写入全 0 日期 - 相反它抛出错误“列 'XXXX' 不能为空”。我通过将组参数 explicit_defaults_for_timestamp 设置为 0 解决了这个问题,然后允许将时间戳列插入/更新为 null 而不会出错。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-04
        • 2016-03-06
        • 2012-01-29
        相关资源
        最近更新 更多