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

发布于 2025-01-16 03:27:47 字数 492 浏览 3 评论 0原文

我很惊讶地发现 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")
)

I was rather surprised to find out that jOOQ (as of 3.16) binds timestamp to LocalDateTime. In my mind timestamp is most naturally mapped to an Instant, it is a Unix epoch timestamp.

So how can we get jOOQ to generate code that uses Instant instead of LocalDateTime? Do I need to use a force generator?

I tried using forced type like this but it never picks up my forced type.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烦人精 2025-01-23 03:27:47

关于 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 规范,或者从存在像 java.sql.Timestamp.valueOf(LocalDateTime)<代码> java.sql.Timestamp.toLocalDateTime()

事实上,您更喜欢使用 java.time.Instant ,这暗示在 PostgreSQL 中使用 TIMESTAMP WITH TIME ZONE 会更好,JDBC(以及 jOOQ)将其映射到 <默认情况下为代码>OffsetDateTime。您可以在 jOOQ 中将该类型重写为 INSTANT,而无需转换器:
https://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")

On PostgreSQL timestamp data types

In PostgreSQL (I'm assuming you're using PG), TIMESTAMP is short for TIMESTAMP WITHOUT TIME ZONE as documented here: https://www.postgresql.org/docs/current/datatype-datetime.html

The best Java types to map that to are:

  • java.sql.Timestamp (the old JDBC type, whose valueOf() and toString() behaviours do not support time zones and also work with your local time zone)
  • java.time.LocalDateTime

You can see this also in the JDBC spec, or derive it from the fact that there are methods like java.sql.Timestamp.valueOf(LocalDateTime) and java.sql.Timestamp.toLocalDateTime().

The fact that you prefer working with java.time.Instant hints at it being better to use TIMESTAMP WITH TIME ZONE in PostgreSQL, which JDBC (and thus jOOQ) maps to OffsetDateTime by default. You can rewrite that type without a converter to INSTANT in jOOQ:
https://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-database/codegen-database-forced-types/

You can also see this recommendation in the PostgreSQL wiki:
https://wiki.postgresql.org/wiki/Don't_Do_This#Don.27t_use_timestamp_.28without_time_zone.29

Your specific configuration

Regarding your specific attempts to map the type:

.withIncludeExpression("timestamp")

That only applies to column named timestamp. You probably meant to apply your forced type to type names?

.withIncludeTypes("timestamp")
风追烟花雨 2025-01-23 03:27:47

卢卡斯·埃德尔很高兴地给出了几乎完整的解决方案提示
使用文档中的转换器 - 您始终可以实现自己的数据类型绑定

我们需要定义一个 Converter

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")

人们可以使用它深思熟虑,牢记原始答案

Gladly Lukas Eder gave as an almost complete hint to a solution
using converters from docs - You can always implement your own data type binding

We need to define a Converter

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

And a little tweak in codegen

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

One can use this thoughtfully, with an original answer in mind

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文