【问题标题】:Copying TIMESTAMP to DATETIME on MySQL with Hibernate使用 Hibernate 在 MySQL 上将 TIMESTAMP 复制到 DATETIME
【发布时间】:2017-07-08 23:47:24
【问题描述】:

我有这两个课

class Source {
    // mapped to TIMESTAMP
    @Version
    @Column(columnDefinition="TIMESTAMP(3) DEFAULT '2016-01-01'")
    Instant myInstant;
}

class Destination {
    // mapped to DATETIME
    @Basic(optional=true)
    Instant myInstant;
}

使用 Hibernate 时,我分配

destination.myInstant = source.myInstant;

然后存储的值比原始值小一小时 - 根据命令行 MySQL 客户端和 Java。我现在的时区是UTC+1,所以原因很明显是时区转换。

有几个地方可以解决此问题,但我正在寻找最佳做法。服务器应该在全球范围内工作,所以它应该继续在内部使用 UTC,对吧?

我应该将列类型更改为TIMESTAMP 吗?那么,为什么Instant默认映射到DATETIME呢?


根据this articleInstant 确实映射到TIMESTAMP,但在我的情况下它没有。为什么?

【问题讨论】:

  • 请提供SHOW CREATE TABLE和从Hibernate生成的SQL。
  • @RickJames 没有什么有趣的地方:SHOW CREATE TABLE 显示了像 timestamp(3) NOT NULL DEFAULT '2016-01-01 01:00:00.000datetime 这样的类型。这些语句只是简单的选择和更新,没有背后的逻辑。这些值没有被记录。无论如何我都会发布日志,但我必须用我的问题中使用的那些替换真实的类和字段名称,这是不值得的,因为那里真的什么都没有。
  • SHOW VARIABLES LIKE '%zone%';
  • @RickJames system_time_zone = UTC , time_zone = SYSTEM.
  • 但是你说“我当前的时区是 UTC+1”——这是从哪里来的?

标签: java mysql hibernate datetime


【解决方案1】:

如果您想使用时区和 Java 8,我建议使用 ZonedDateTime 或 OffsetTimeZone(使用 Hibernate 时首选后者)。对于旧版本,请使用日历。

  • 当您实例化时,它应该默认使用您计算机的时区。
  • 检查数据库是否为带或不带时区的时间戳。
  • 你设置的默认也是不带时区的,如果是“带时区”,它应该自动添加数据库的偏移量。

我希望其中一些有效。以下是我在其中一个项目中的表现。

@Column(name = "registration_time")
private OffsetDateTime registrationTime;
[...]
subscriber.setRegistrationTime(OffsetDateTime.now());

【讨论】:

  • 我对你的回答并不完全满意,但这不是你的错。我将不得不调查更多实际发生的事情(请参阅我对 Rick James 的回答)。
【解决方案2】:

在 MySQL 5 及以上版本中,TIMESTAMP 值从当前时区转换为 UTC 进行存储,并从 UTC 转换回当前时区以进行检索。这仅适用于 TIMESTAMP 数据类型,而不适用于 DATETIME。这就是您在将 TIMESTAMP 分配给 DATETIME 时看到差异的原因。因此,拥有相同类型的两个列应该可以工作。 Hibernate 默认将 InstantType 映射到数据库 TIMESTAMP 类型。虽然您可以将它用于 MYSQL 中的 TIMESTAMP 和 DATETIME,但它们的处理方式不同。

【讨论】:

    猜你喜欢
    • 2016-02-25
    • 2017-01-25
    • 2015-04-20
    • 2016-10-30
    • 2011-02-01
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多