0

我想使用Instant类型将其放入 MySQL 数据库(timestamp字段)。不幸的是,当使用 POJO 和 时Record#from(),出于某种原因,jOOQ 不允许我这样做。我的 gradle 配置有以下内容:

forcedTypes {
    forcedType {
        name = "Instant"
        types = "timestamp"
    }
}

代码正在正确生成,但不起作用并在运行时给我错误:

 Data truncation: Incorrect datetime value: '2021-01-16 05:01:25.457+00:00' for column `test`.`messages`.`time_sent` at row 1

我尝试添加自己的转换器和活页夹,但如果在 gradle config 中设置它们似乎不起作用name,因为在构建过程中会出现警告。但是没有name我就无法让 jOOQInstanttimestamp字段生成。

使用 jOOQ 的 POJO 时有没有办法Instant与 SQL一起使用?timestamp

4

1 回答 1

2

MySQL 的时间戳数据类型有点愚蠢。

它以 32 位整数的形式将时间存储为自纪元(1970 年 1 月 1 日,UTC,午夜)以来的秒数。这有几个问题:

  • 没有毫秒的空间。你的 Instant 有.457毫秒,这需要被去掉,这就是 JOOQ 拒绝这样做的原因;那是破坏数据。我假设您不关心那些毫秒,但 JOOQ 不知道这一点。您可以尝试从瞬间中去除毫秒,如果必须的话,JOOQ 可能会允许保存瞬间,如果该瞬间具有它所环绕的纪元可被 1000 整除的属性(没有毫秒部分)。除了,这很烦人,所以在某些时候,即使它存储为 32 位 seconds-since-epoch,数据类型现在也单独包含从 0 到 999999 的小数秒。要么你有一个旧版本的 MySQL或者不允许这样做的底层表结构,或者 JOOQ 不知道 MySQL 至少支持毫秒。
  • 在 2038-01-19 03:14:07 UTC,您的应用程序爆炸。而已。这是 MySQL TIMESTAMP 对象可表示的最后一个时间戳。我们距此不到 18 年。因此,这种数据类型实际上是不可用的,你应该使用别的东西。(这对你来说可能听起来不可信。如果你需要一些令人信服的信息,请仔细阅读 MySQL8 的用户手册 §11.2.2,直接从源头获取)。Java 的核心即时存储系统不会受到可怕的 Y2K38 的影响,因为 java 在 64 位中使用 millis-since-epoch;在这个数字用完之前,我们还有几十亿年的时间。
  • 请注意,打印的消息有点误导。瞬间存储为自纪元以来的毫秒数,并且没有时区,+00.00在打印输出中表明它确实如此。它没有——因此 mysql 的 TIMESTAMP 类型也不是问题。

解决方案

到目前为止,最好的解决方案是使用不会像这样损坏的数据库引擎。例如,尝试 postgres。

另一个遥远的第二个解决方案是仔细阅读JOOQ 问题 #9665,其中@lucaseder(JOOQ 的核心贡献者;他是在那里施展魔法的天才:P)说它还不起作用,但那里有一些代码你可以使用.

请注意,如果您真的关心区域,这将变得更加复杂。有 3 种不同的方式来表示时间;这些是不同的,如果没有额外的信息和警告,就不能相互转换;无论如何,大多数工具都会错误地默默地转换它们,并且当这种情况发生时会产生痛苦。因此,您可能想考虑一下您在这里拥有的 3 种时间中的哪一种:

  • solarflares time:某事发生或将要发生的时刻,例如太阳耀斑。如果某个政治实体决定更改时区,则无效。无论时区发生什么,“事件发生前的时间”/“事件发生后的时间”每秒都会增加 1 秒。在 Java 术语中,java.time.Instant.
  • 预约时间:我给阿姆斯特丹的理发师打电话,预约时间是 2023 年 1 月 5 日 14:00。你会认为这就像太阳耀斑时间,但是,不。如果荷兰议会猛烈抨击木槌并通过一项法律,荷兰将不再遵守夏令时并将继续在夏季,那么木槌落下的那一刻,距离我的约会的秒数增加了一个小时(是不是减少一个小时?)。这一点都不奇怪——参见欧盟指令 2000/84/EC——事实上,它很有可能。Solarflares 的时间不应该像这样改变,而预约时间会改变。最好表示为年+月+日+小时+分钟+秒+毫秒+一个完整区域(即,而不是像or之类的Europe/Amsterdam愚蠢无用的东西)。在 Java 术语中,.+0800PSTZonedDateTime
  • 闹钟时间:只有年、月、日、时、分、秒。就是这样 - 它不代表任何特定的东西,而只是概念。如果我设置闹钟在早上 8 点叫醒我,然后我穿越太平洋旅行,那么当我移动时区时,闹钟响起的时间应该会发生巨大变化。在java方面,LocalDateTime和朋友。

我假设您有一个 solarflares 时间(例如,跟踪“用户 X 在此时更改他们的密码”)。这个答案假设你是这个意思。如果你不这样做,我的建议会有所改变。大多数情况下,整个“不要使用 mysql”会变得更加强大:你真正想要的是postgresTIMESTAMP WITH TIME ZONE之类的数据类型。

于 2021-01-17T06:20:41.887 回答