You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Criteria Builder根据年份筛选数据库完整日期数据

解决Criteria Builder按年份筛选日期字段的问题

核心问题分析

你之前的代码只做了「大于等于当年第一天」的判断,没有限制年份上限,所以会把后续所有年份的数据都包含进来,导致结果超出预期。要精准筛选某一年的所有日期,需要同时限定当年第一天和下一年第一天的范围(或者当年最后一天)。

正确实现代码

以下是两种可靠的实现方式,优先推荐第二种(避免最后一天的时间边界问题,比如数据库字段带时分秒的情况):

if (yearCreated.isPresent()) {
    int targetYear = Integer.parseInt(yearCreated.get());
    LocalDate startOfTargetYear = LocalDate.of(targetYear, 1, 1);
    LocalDate startOfNextYear = startOfTargetYear.plusYears(1);

    // 方式1:使用between(适合纯LocalDate字段,无时分秒)
    predicates.add(criteriaBuilder.between(
        root.get("yearCreated"), 
        startOfTargetYear, 
        startOfNextYear.minusDays(1)
    ));

    // 方式2:组合大于等于+小于(更通用,兼容LocalDateTime字段)
    // predicates.add(criteriaBuilder.and(
    //     criteriaBuilder.greaterThanOrEqualTo(root.get("yearCreated"), startOfTargetYear),
    //     criteriaBuilder.lessThan(root.get("yearCreated"), startOfNextYear)
    // ));
}

备选方案:提取年份匹配

如果不介意索引失效的风险(日期字段有索引时,函数提取年份会跳过索引),可以直接提取数据库日期的年份进行匹配:

if (yearCreated.isPresent()) {
    int targetYear = Integer.parseInt(yearCreated.get());
    // 注意:不同数据库的年份函数名大多一致(MySQL/Oracle/H2都是YEAR),需根据实际调整
    predicates.add(criteriaBuilder.equal(
        criteriaBuilder.function("YEAR", Integer.class, root.get("yearCreated")),
        targetYear
    ));
}

为什么之前的代码失效?

你原来的代码调用criteriaBuilder.localDate()的方式有误,而且只设置了下限条件,没有上限,导致查询结果包含目标年份及之后所有年份的数据,自然不符合预期。

内容的提问来源于stack exchange,提问作者Helio Brito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 19:02:33