在 JOOQ 中,我们如何使用 Java Instant 映射到 Postgresql 时间戳类型?

In JOOQ how do we use Java Instant to map to Postgresql's timetamp type?

我很惊讶地发现 JOOQ(截至 3.16)将时间戳绑定到 LocalDateTime。在我看来,时间戳最自然地映射到一个 Instant,它是一个 Unix 纪元时间戳。

那么我们如何让 JOOQ 生成使用 Instant 而不是 LocalDateTime 的代码呢?我需要使用力发生器吗?

我试过像这样使用强制类型,但它从来没有选择我的强制类型。

                            .withForcedTypes(
                                    new ForcedType()
                                            .withUserType(Instant.class.getCanonicalName())
                                            .withConverter(com.monsolei.data.InstantConverter.class.toString())
                                            .withIncludeExpression("timestamp")
                            )

关于 PostgreSQL 时间戳数据类型

在 PostgreSQL 中(我假设您使用的是 PG),TIMESTAMPTIMESTAMP WITHOUT TIME ZONE 的缩写,如此处记录:https://www.postgresql.org/docs/current/datatype-datetime.html

映射到的最佳 Java 类型是:

  • java.sql.Timestamp(旧的 JDBC 类型,其 valueOf()toString() 行为不支持时区,但也适用于您当地的时区)
  • java.time.LocalDateTime

您也可以在 JDBC spec, or derive it from the fact that there are methods like java.sql.Timestamp.valueOf(LocalDateTime) and java.sql.Timestamp.toLocalDateTime() 中看到它。

您更喜欢使用 java.time.Instant 这一事实暗示在 PostgreSQL 中使用 TIMESTAMP WITH TIME ZONE 更好,JDBC(因此 jOOQ)映射到 OffsetDateTime默认。在 jOOQ 中,您可以在没有转换器的情况下将该类型重写为 INSTANThttps://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-database/codegen-database-forced-types/

您还可以在 PostgreSQL wiki 中看到此推荐: https://wiki.postgresql.org/wiki/Don't_Do_This#Don.27t_use_timestamp_.28without_time_zone.29

您的具体配置

关于您映射类型的具体尝试:

.withIncludeExpression("timestamp")

这仅适用于名为 timestamp 的列。您可能打算将强制类型应用于类型名称?

.withIncludeTypes("timestamp")

很高兴 Lukas Eder 给出了几乎完整的解决方案提示 使用来自文档的转换器 - You can always implement your own data type binding

我们需要定义一个转换器

class JooqInstantConverter: Converter<LocalDateTime, Instant> {

  override fun to(databaseObject: Instant?): LocalDateTime? {
    if (databaseObject == null)
      return null
    return LocalDateTime.ofInstant(databaseObject, ZoneOffset.UTC)
  }

  override fun from(userObject: LocalDateTime?): Instant? {
    return userObject?.toInstant(ZoneOffset.UTC)
  }

  override fun toType(): Class<Instant> {
    return Instant::class.java
  }

  override fun fromType(): Class<LocalDateTime> {
    return LocalDateTime::class.java
  }
}

并对 codegen 进行一些调整

ForcedType()
  .withUserType("java.time.Instant")
  .withConverter("xxx.JooqInstantConverter")
  .withTypes("TIMESTAMP")

人们可以考虑周到地使用它,并牢记