使用Hibernate在MySQL上将TIMESTAMP复制到DATETIME

2022-09-04 22:53:59

我有这两个类

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;
}

使用休眠时,我分配

destination.myInstant = source.myInstant;

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

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

我应该将列类型更改为 ?那么,为什么默认情况下映射到 ?TIMESTAMPInstantDATETIME


根据这篇文章映射到 ,但在我的情况下它没有。为什么?InstantTIMESTAMP


答案 1

如果你想使用时区和Java 8,我建议你使用ZonedDateTime或OffsetTimeZone(后者在使用Hibernate时更受欢迎)。对于旧版本,请使用日历。

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

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

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

答案 2

在MySQL 5及更高版本中,TIMESTAMP值从当前时区转换为UTC进行存储,并从UTC转换回当前时区以进行检索。这仅对 TIMESTAMP 数据类型发生,而不对 DATETIME 发生。这就是您在为日期时间分配时间戳时看到差异的原因。因此,拥有相同类型的两个列应该有效。默认情况下,休眠将 InstantType 映射到数据库 TIMESTAMP 类型。虽然您可以在MYSQL中同时将其用于TIMESTAMP和DATETIME,但它们的处理方式不同。