1. 简介

本文将介绍如何在 Spring Data JPA 中基于日期和时间字段查询实体。

我们先回顾一下 JPA 中日期与时间的映射方式,然后定义一个包含日期时间字段的实体类,并创建对应的 Spring Data 仓库接口来实现查询功能。内容简单粗暴,直奔主题,适合有经验的开发者快速查阅和踩坑参考。

2. JPA 中的日期与时间映射

在正式查询前,先温习一下 JPA 如何映射日期和时间类型。你需要明确字段表示的是:

  • 仅日期(年月日)
  • 仅时间(时分秒)
  • 还是日期+时间(时间戳)

除了可选的 @Column 注解外,还需要使用 @Temporal 注解来指定字段的语义类型。该注解接收一个 TemporalType 枚举值作为参数,包括:

  • TemporalType.DATE —— 只保留年月日(如:2025-04-05)
  • TemporalType.TIME —— 只保留时分秒(如:14:30:00)
  • TemporalType.TIMESTAMP —— 保留完整的时间戳(如:2025-04-05 14:30:00)

⚠️ 注意:虽然 Java 8 引入了 LocalDateTimeZonedDateTime 等新时间类型,可以直接被 JPA 2.2+ 支持而无需 @Temporal,但如果你还在用 java.util.Datejava.util.Calendar,那就必须加上 @Temporal,否则可能踩坑。

更详细的 JPA 时间类型映射说明可参考 这篇文章

3. 实战示例

一旦实体类正确配置,Spring Data JPA 的查询机制就能无缝支持日期时间字段。你可以使用:

  • ✅ 方法名推导(Query Methods)
  • @Query 注解写原生或 JPQL 查询

下面通过一个实际例子演示。

3.1. 定义实体类

假设我们有一个 Article 文章实体,包含发布日期、发布时间以及创建时间戳:

@Entity
public class Article {

    @Id
    @GeneratedValue
    Integer id;
 
    @Temporal(TemporalType.DATE)
    Date publicationDate;
 
    @Temporal(TemporalType.TIME)
    Date publicationTime;
 
    @Temporal(TemporalType.TIMESTAMP)
    Date creationDateTime;
}

📌 说明:这里特意把“发布时间”拆成 publicationDatepublicationTime 两个字段,是为了覆盖三种 TemporalType 类型,便于演示。

3.2. 创建 Repository 查询接口

接下来定义 Spring Data 的 ArticleRepository,实现三个典型的时间查询场景:

public interface ArticleRepository 
  extends JpaRepository<Article, Integer> {

    List<Article> findAllByPublicationDate(Date publicationDate);

    List<Article> findAllByPublicationTimeBetween(
      Date publicationTimeStart,
      Date publicationTimeEnd);

    @Query("select a from Article a where a.creationDateTime <= :creationDateTime")
    List<Article> findAllWithCreationDateTimeBefore(
      @Param("creationDateTime") Date creationDateTime);
}

逐个解释:

方法名 查询逻辑 使用机制
findAllByPublicationDate 查询指定发布日期的文章 Query Method(按日期匹配)
findAllByPublicationTimeBetween 查询发布时间在某个时间段内的文章 Query Method(时间区间)
findAllWithCreationDateTimeBefore 查询创建时间早于某时刻的文章 @Query + JPQL

✅ 关键点:

  • 第一个方法只比较 日期部分(忽略时分秒)
  • 第二个方法只比较 时间部分(忽略年月日)
  • 第三个方法则完整比较 日期+时间

也就是说,Spring Data JPA 会根据字段上的 @Temporal 类型自动截取参数中的对应部分进行匹配,无需手动处理。

3.3. 编写测试验证查询

最后写几个集成测试,验证查询是否按预期工作。

@RunWith(SpringRunner.class)
@DataJpaTest
public class ArticleRepositoryIntegrationTest {

    @Autowired
    private ArticleRepository repository;

    @Test
    public void whenFindByPublicationDate_thenArticles1And2Returned() throws Exception {
        List<Article> result = repository.findAllByPublicationDate(
          new SimpleDateFormat("yyyy-MM-dd").parse("2018-01-01"));

        assertEquals(2, result.size());
        assertTrue(result.stream()
          .map(Article::getId)
          .allMatch(id -> Arrays.asList(1, 2).contains(id)));
    }

    @Test
    public void whenFindByPublicationTimeBetween_thenArticles2And3Returned() throws Exception {
        List<Article> result = repository.findAllByPublicationTimeBetween(
          new SimpleDateFormat("HH:mm").parse("15:15"),
          new SimpleDateFormat("HH:mm").parse("16:30"));

        assertEquals(2, result.size());
        assertTrue(result.stream()
          .map(Article::getId)
          .allMatch(id -> Arrays.asList(2, 3).contains(id)));
    }

    @Test
    public void givenArticlesWhenFindWithCreationDateThenArticles2And3Returned() throws Exception {
        List<Article> result = repository.findAllWithCreationDateTimeBefore(
          new SimpleDateFormat("yyyy-MM-dd HH:mm").parse("2017-12-15 10:00"));

        assertEquals(2, result.size());
        assertTrue(result.stream()
          .map(Article::getId)
          .allMatch(id -> Arrays.asList(2, 3).contains(id)));
    }
}

📌 测试要点:

  • 所有 SimpleDateFormat 都需正确设置格式,避免解析错误
  • 注意时区问题(本例默认使用系统时区)
  • @DataJpaTest 提供了内存数据库环境,适合做轻量级集成测试

测试通过说明:三个查询都能准确按日期、时间或时间戳过滤数据,在真实项目中可直接套用。

4. 总结

本文演示了如何在 Spring Data JPA 中基于日期和时间字段进行查询:

  • 使用 @Temporal 明确字段语义(DATE / TIME / TIMESTAMP)
  • 利用 Query Method 或 @Query 实现灵活查询
  • Spring Data 会自动根据 TemporalType 截取参数的有效部分进行比较
  • 测试验证是确保逻辑正确的关键步骤

✅ 推荐实践:

  • 新项目建议使用 Java 8 时间 API(如 LocalDateTime),避免 Date 类型的坑
  • 若必须用 Date,务必加上 @Temporal 注解
  • 时间查询容易受时区影响,建议统一使用 UTC 存储

本文完整源码已发布在 GitHub:https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-jpa-query-3


原始标题:Query Entities by Dates and Times with Spring Data JPA