我相当惊讶地发现 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 中(我假设您使用的是 PG),
TIMESTAMP
是 TIMESTAMP 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")
很高兴 Lukas Eder 给出了几乎完整的解决方案提示 使用文档中的转换器 - 您始终可以实现自己的数据类型绑定
我们需要定义一个转换器
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
}
}
在代码生成中进行一些调整
ForcedType()
.withUserType("java.time.Instant")
.withConverter("xxx.JooqInstantConverter")
.withTypes("TIMESTAMP")
人们可以深思熟虑地使用它,并牢记原始答案