【问题标题】:Why JPA does not support java.time.Instant?为什么 JPA 不支持 java.time.Instant?
【发布时间】:2018-08-24 19:58:15
【问题描述】:

我认为java.time.Instant 是将日期存储到数据库中的最佳选择:它最有可能是TIMESTAMP,并且您不依赖于时区,它只是时间上的一个时刻。

JPA 支持LocalDateLocalTimeLocalDateTime 等,但不支持 Instant。当然,您可以使用 AttributeConverter 或像 Jadira 这样的一些库,但为什么不支持开箱即用?

【问题讨论】:

  • 请注意,Hibernate 5 支持它。
  • 我知道。但是今天在与我的同事讨论时出现了一个想法,即您不应该使用 Instant,因为 JPA 不支持它。我想知道为什么?
  • DataNucleus JPA 在 Java 8 之前就已经支持它!一个简单的事实是,Oracle 对 JPA API 很懒惰,并且懒得向它提交资源,因此 JPA 2.2 中的项目很少,这是他们遗漏的类型
  • RE:您的第一句话:(a) 是的,使用java.time.Instant 来表示一个时刻,例如SQL 标准的TIMESTAMP WITH TIME ZONE 列。是的,Instant 替换了 java.util.Datejava.sql.Timestamp 类。 (b) 不,“不取决于时区”是不正确的。在Instant: UTC 上一个时区。至于数据库,这种行为会有所不同。例如,在 Postgres 中,TIMESTAMP WITH TIME ZONE 列的输入使用任何提供的区域/偏移信息来调整为 UTC 进行存储,然后在调整完成后丢弃提供的区域/偏移信息。
  • 忽略在本页和其他地方看到的关于使用 java.time.LocalDateTime 的错误建议。该类确实代表一个时刻,因为它故意缺少任何区域/偏移的概念。该类别是不确定的,代表了一个关于在大约 26-27 小时(全球时区范围)范围内潜在时刻的粗略概念。

标签: java jpa java.time.instant


【解决方案1】:

我会再试一次。 the issue 中有一些讨论。最近的讨论似乎是:

mkarg 说:虽然这绝对正确,但技术上的答案是 更复杂一点:构成数据类型的最终谓词是什么 有资格包含在强制类型映射集中吗?

可以说,谓词是“必要的”或“共同的” 使用”,但谁来定义什么是“基本”或“常用”?见,对于 一些应用程序,对 java.awt.Image 和 java.net.URL 的支持可能 比支持 LocalDate 或 ZonedDateTime 更重要。在 另一方面,其他应用程序可能充满了 LocalDate 但 从不使用 Instant。那么具体在哪里进行切割呢?这变成 在查看发现的大量类型时特别复杂 在 JRE 中,很明显必须在某个地方进行剪辑。甚至 与 JRE 捆绑在一起的 JavaFX 仍然不支持 Instant 在 v8 中,为什么要 JPA?看看目前的进展 Project Jigsaw,可能的限定谓词可能只是 由“特定拼图模块中的所有类型”回答?

无论如何,这不是由我决定的。我支持你的要求,并且 希望看到对所有 Java Time API 时间的支持, 特别是对于 Instant 和 Duration,并且您的请求具有显着性 像我学到的 Java Champion Arun Gupa 这样的支持者 最近。但我怀疑最终的答案是否会如此简单和令人满意 因为我们很想拥有它。

也许最好简单地设置另一个 JSR,比如“Common Java 平台的数据类型转换”,它提供了更多 映射不仅仅是日期和时间,也不会绑定到 JPA 但也可以被 JAXB、JAX-RS 和可能的更多 API 使用 处理“转”的问题是什么?拥有这样的车辆 确实会大大减少样板文件。

TL-DR;有很多类型。我们必须在某处划清界限。

a new issue 可以将其添加到未来的 JPA 版本中。

Douglas Surbera thread 上发现的另一个有趣的分析(适用于 JDBC):

JDK 8 版本的 JDBC 包括对大多数 SQL 类型的支持 对应 310 个类。

  • 日期 - 本地日期
  • 时间 - 本地时间
  • 没有时区的时间戳 - LocalDateTime
  • 带有时区的时间戳 - 偏移日期时间

JDK 8 版本的 JDBC 不包括 INTERVAL 之间的映射 类型和对应的310个类。

没有与任何其他 310 完全对应的 SQL 类型 类。因此,JDBC 规范对所有其他类都保持沉默。

我强烈鼓励 JDBC 开发人员使用新的 310 类。 java.util.Date、java.sql.Date有问题, java.sql.Time 和 java.sql.Timestamp。你应该考虑他们 已弃用。 310 类非常优越。

道格拉斯

TL:DR;我们刚刚为您在数据库中存储时态数据的 4 种可能方式中的每一种选择了一种 Java 8 类型。

最后,如果您通读 this thread,似乎存在着使标准 API 保持小而简单的巨大文化压力。

【讨论】:

  • 对我来说存储 LocalDate (LocalTime, LocalDateTime) 不是一个好方法,因为他们正在使用 TimeZone 但没有存储它,所以你的应用程序应该在一个 TimeZone 中使用,或者你应该存储其他列中的时区或(我认为最常用的情况)将此日期存储在 UTC 中,并在每次请求时将其转换为所需的时区。
  • 如果您需要存储时区,请使用OffsetDateTime
  • 问题是我不需要特定的时区,我将从浏览器获得的时区,我会调整即时到所需的时区
  • 以一种扭曲的方式,这实际上比Instant 更灵活,因为如果您的数据库已经有很多现有数据(或另一个应用程序正在创建数据),这些数据存储为没有时区的时间戳但不是在 UTC 中,那么 JPA 将不知道如何将其映射到瞬间。这样,如果您要映射没有时区信息的列,则必须指定存储数据的时区。
  • 这不是您所指的“新问题”。这是一个要求支持所有合理的 java.time 类型的老问题,正如它所显示的那样,Oracle 代表单方面决定他只支持 JPA 2.2 规范中的一个子集。 “新问题”就是这个github.com/javaee/jpa-spec/issues/163
【解决方案2】:

这不是 JPA 问题,而是 JDBC 问题。

JDBC 支持 Date、Timestamp、LocalDate、LocalTime 和 LocalDateTime 但不支持即时

这不是 Java 问题,而是 SQL 问题,数据库中存储的内容是年-月-日-时-分-秒结构。

想想 SQL 函数: 年() 月() 等等……

这些函数不能应用于自 1970 年以来的简单毫秒编码。它们确实需要 LocalDateTime 构造来执行这些功能。

【讨论】:

  • 这个答案完全不正确。 (A) JDBC 4.2 及更高版本支持java.time:参见方法PreparedStatement::setObjectResultSet::getObject。这种支持包括Instant。 (B) LocalDateTime 完全是错误的类,因为它缺少任何时区或与UTC 偏移的概念。所以LocalDateTime 确实 代表一个时刻,是不是 时间线上的一个点,并且不能用于表示从1970-01 计数的数字-01T00:00Z 纪元参考。
  • (C)它一个JPA问题。 Hibernate already supports java.time 包括 Instant。从我有限的阅读(我不是用户)来看,负责 JPA 的人懒惰或不称职似乎是一个问题。
  • @Basil Bourque 有人这么认为(关于懒惰或无能),但在这种情况下,最简单的方法是实现 Instant - 这是一个 TIMESTAMP,不要在 LocalDate、LocalTime 等上浪费时间.
  • @Filosssof 是的,作为一种解决方法,您可能需要使用java.sql.Timestamp。但是通过调用添加到旧的旧日期时间类的新转换方法立即转换为 java.time 类:Instant instant = myJavaSqlTimestamp.toInstant() ;。那些遗留的日期时间类是糟糕的设计和黑客的一团糟——避免/尽量减少它们的使用。 java.time 框架的构建是为了替换那些旧类,原因有很多。
猜你喜欢
  • 2019-07-05
  • 2021-12-12
  • 2018-03-31
  • 1970-01-01
  • 2011-03-17
  • 2018-07-21
  • 2013-01-04
  • 2017-10-07
  • 2011-09-16
相关资源
最近更新 更多