【问题标题】:JPA and Hibernate: compare only time portions of timestampsJPA 和 Hibernate:仅比较时间戳的时间部分
【发布时间】:2012-11-01 16:40:59
【问题描述】:

我正在通过 JPA 使用 Hibernate,我需要按 Date 属性的时间部分过滤记录。

public class Foo {
    Date getDateTime() {
        // Returns a date and time value.
    }
}

Time startTime = ...;
Time endTime = ...;

TypedQuery<Foo> query = entityManager.createQuery("SELECT foo FROM Foo foo where :startTime <= foo.dateTime AND foo.dateTime <= :endTime", Foo.class);
query.setParameter("startTime", startTime);
query.setParameter("endTime ", endTime);

这当然行不通,因为您无法直接比较 DateTime。如果这是一个 SQL 查询,那么我会使用一些 DBMS 特定的日期函数来比较它们,但是在 JPA 中如何比较日期和时间呢?

【问题讨论】:

  • 您在使用 java.sql.Time 吗?
  • 只是为了澄清......您想查询具有 datetime 列的记录,但仅与该列的 hh:mm:ss.SSS 组件进行比较。或者换一种说法,“给我一天中某个时间发生的所有记录”。对吗?
  • @kaliatech 前者是正确的。

标签: java hibernate jpa jpql


【解决方案1】:

如果您使用的是 JPA,您可以使用 @Temporal(TemporalType.TIME) 它将仅返回 TIMESTAMP 的时间部分。 喜欢: @Temporal(TemporalType.TIME) 日期 getDateTime()

【讨论】:

    【解决方案2】:

    为什么不使用本机查询,然后利用您熟悉的数据库特定功能。拥有 Native Query 后,您可以将 java.sql.Time 对象转换为 long 并执行它。

    EntityManager API Documentation

    例如,如果您使用的是 Oracle。

                long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
        long startTimeMillis = (startTime.getTime() % MILLIS_PER_DAY)/1000;
        long stopTimeMillis = (endTime.getTime() % MILLIS_PER_DAY)/1000;
        entityManager
                .createNativeQuery(
                        "select * from foo where to_number(to_char(date_time, 'sssss')) between ?1 and ?2", Foo.class)
                .setParameter(1, startTimeMillis)
                .setParameter(2, stopTimeMillis).getResultList();
    

    实际查询将根据您的数据库风格而有所不同,但是创建 NativeQuery 应该允许您利用特定于您的数据库的底层供应商功能。

    解决此挑战的另一种方法是创建一个视图,该视图包含一个列,该列包含具有日期数据类型的列的时间部分。这将允许您以在代码中透明的方式利用底层数据库技术。设置此列后,您将在查询中建立正确的 where 子句。

    【讨论】:

    • 如果 'sssss' 从午夜返回秒数(不是毫秒),那么我认为您需要先将 startTimeMillis 和 stopTimeMillis 除以 1000,然后再将它们作为查询参数插入。
    • @kaliatech 说得好,我当然错过了。有没有办法告诉 Oracle 从午夜返回毫秒?
    • 我不知道有什么简单的方法可以使用 to_char。不过这里是one possible solution
    【解决方案3】:

    没有任何简单或标准化的方法可以仅与使用 JPA2 的现有日期时间/时间戳列的时间(或日期)组件进行比较。选项:

    1. 使用原生查询。如果您需要秒精度(不是毫秒),kmb385's answer 可以工作。我认为更常见的原生 SQL 方法是使用 CAST 或 EXTRACT 仅与时间分量进行比较。

    2. 将另一列添加到仅包含日期时间的时间组件的表/视图,并使用它进行比较。您可能还会使用 @Temporal(TemporalType.TIME) 注释向 Foo 添加另一个字段。

    【讨论】:

    • 只是好奇为什么我的方法不能只匹配时间部分?
    • 我最初误解了 'sssss' 格式在 Oracle 中的作用。我刚才查了一下,并同意,你的答案会按预期工作(有一个小的更正,我会在评论中注明)。我现在将编辑我的答案以避免混淆。
    猜你喜欢
    • 2017-04-23
    • 2019-03-17
    • 1970-01-01
    • 2014-09-21
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多