我正在使用jooq(v3.11.9(来访问以UTC时间运行的MySQL数据库。我使用了生成的实体,并且正在使用 JSR-310 时间类型。我在配置中使用的选项:
<javaTimeTypes>true</javaTimeTypes>
我的理解是,MySQLdatetime
和timestamp
类型都映射到LocalDateTime
这是有道理的,因为 MySQL 不会将时区信息与时间一起存储。但是,当我在不同的时区(在我的例子中是 EST(的计算机上运行查询时,即使会话时区是 UTC,日期也都在我的本地计算机时区中。
我已确认会话时区为 UTC
dslContext.fetch("SELECT @@system_time_zone, @@global.time_zone, @@session.time_zone;")
返回
|@@system_time_zone|@@global.time_zone|@@session.time_zone|
+------------------+------------------+-------------------+
|UTC |SYSTEM |SYSTEM |
+------------------+------------------+-------------------+
时区转换示例:
dslContext.select(MY_TABLE.EPOCH_DT_TM, MY_TABLE.CREATION_TIMESTAMP).from(MY_TABLE).limit(1).fetch()
+-----------------------+-----------------------+
|epoch_dt_tm |creation_timestamp |
+-----------------------+-----------------------+
|2019-04-18T13:57:39.163|2019-09-24T16:06:47.754|
+-----------------------+-----------------------+
// CAST to STRING PROPERLY USES SESSION TIMEZONE
dslContext.select(MY_TABLE.EPOCH_DT_TM.cast(org.jooq.impl.SQLDataType.VARCHAR(100)), MY_TABLE.CREATION_TIMESTAMP.cast(org.jooq.impl.SQLDataType.VARCHAR(100))).from(MY_TABLE).limit(1).fetch()
+--------------------------+--------------------------+
|cast |cast |
+--------------------------+--------------------------+
|2019-04-18 17:57:39.163000|2019-09-24 20:06:47.754000|
+--------------------------+--------------------------+
我生成的实体中的字段:
public final TableField<MyTableRecord, LocalDateTime> EPOCH_DT_TM = createField("epoch_dt_tm", org.jooq.impl.SQLDataType.LOCALDATETIME, this, "");
public final TableField<MyTableRecord, LocalDateTime> CREATION_TIMESTAMP = createField("creation_timestamp", org.jooq.impl.SQLDataType.LOCALDATETIME.nullable(false).defaultValue(org.jooq.impl.DSL.field("CURRENT_TIMESTAMP(6)", org.jooq.impl.SQLDataType.LOCALDATETIME)), this, "");
所以我的问题是:
这是预期行为吗?记录不应该在表中填充原始(非时区(日期。由于某种原因,日期是否仍在引擎盖下转换为java.sql.Timestamp?
如果这是预期行为,是否有任何方法可以确保获取会话时区中的日期,而不考虑客户端计算机上的本地时区?如果代码的行为取决于计算机时区,则很难在本地进行测试。
提前感谢您的帮助。
我最近发现,根据所使用的数据库驱动程序,jOOQ 可能会在 DateTime 解析中表现出一些奇怪的行为。 jOOQ 将偏移日期时间返回为 Z (UTC(,即使它不是
具体来说,在我的情况下,使用不同的 Postgres 驱动程序会导致 DefaultBinding.java接收具有时间戳的日历对象,但对其调用 toString 以进行解析。 事实证明,toString没有打印时区,然后jOOQ推断它是本地时间。
对我来说,DefaultBinding.java(我使用的是时区时间戳(中的违规行是:
else if (type == OffsetDateTime.class) {
result = (T) offsetDateTime(ctx.resultSet().getString(ctx.index()));
}
您可能在该系列的其他 if 中处于不同的行,基于没有时区。
在我的测试中,我还发现更改系统时间会更改结果,但更改会话时间没有任何作用。
对我来说幸运的是,切换到标准 Postgres 驱动程序解决了这个问题。 如果没有,我将研究重载 OffsetDateTime 的绑定,以修复 toString 的使用及其相关时区的剥离。 不幸的是,您可能需要遵循该路径,除非您也使用可以升级或替换的 SQL 驱动程序。 或者,您可以使用时区存储它,然后在从数据库加载时转换为所需的时区。