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

Spring JPA中where参数为null查询失效问题求助

问题:Spring JPA @Query中参数为null时查询失效

问题复现

复现代码可本地构建,核心代码如下

环境信息

使用Spring Boot Web、JPA、MySQL开发RESTful接口:

  • Spring Boot父版本:2.7.0
  • Java版本:Oracle 11

代码实现

仓库接口

public interface TestRepository extends JpaRepository<Test, Long> {

    @Query("SELECT t FROM Test t WHERE (?1 IS NULL OR t.name LIKE %?1%)")
    Page<Test> findAll(String keyword, Pageable pageable);
}

接口控制器

@GetMapping("/ab")
public Page<Test> ab(CustomPageable pageable) {
    // 测试数据:
    // INSERT INTO test VALUES(1, 'aa', 1);
    // INSERT INTO test VALUES(2, 'a', 2);
    // INSERT INTO test VALUES(3, 'b', 3);
    return testRepository.findAll(pageable.getKeyword(), pageable);
}

CustomPageable模型

public static class CustomPageable extends PageRequest {

    @Getter
    private final String keyword;

    protected CustomPageable(int page, int size, Sort sort) {
        super(page, size, sort);
        keyword = null;
    }

    public CustomPageable(int page, int size, Sort sort, String keyword) {
        super(page, size, sort);
        this.keyword = keyword;
    }
}

问题现象

当pageable.getKeyword()为null时(请求地址:http://localhost:8181/ab?size=3&sort=name,DESC&page=0),期望返回包含3条数据的分页结果,但实际返回空页。

日志信息

2022-10-02 15:40:00.967  INFO 6560 --- [nio-8181-exec-6] p6spy                                    : #1664700000967 | took 2ms | statement | connection 4| url jdbc:mysql://localhost:3306/test
select test0_.id as id1_0_, test0_.name as name2_0_, test0_.status as status3_0_ from test test0_ where ? is null or test0_.name like ? order by test0_.name desc limit ?
select test0_.id as id1_0_, test0_.name as name2_0_, test0_.status as status3_0_ from test test0_ where '%org.hibernate.jpa.TypedParameterValue@d41192d%' is null or test0_.name like '%org.hibernate.jpa.TypedParameterValue@d41192d%' order by test0_.name desc limit 3;

注意查询语句中出现的'%org.hibernate.jpa.TypedParameterValue@d41192d%',这是异常核心点。

补充说明

当传入keyword参数时(请求地址:http://localhost:8181/ab?size=3&sort=name,DESC&page=0&keyword=a),查询结果正常。

问题请求

请解释为何keyword为null时HQL查询失效?是代码问题还是JPA的bug?如何修复该问题?
注意:必须使用@Query注解的HQL实现,请勿推荐CriteriaBuilder等其他方式。


原因分析

这是代码写法导致的参数解析异常,并非JPA bug。具体来说:

  1. HQL中%?1%的写法存在歧义,Hibernate会将%和?1拼接成字符串字面量,而非将?1作为独立参数绑定
  2. 当keyword为null时,Hibernate不会把%?1%解析为%null%,而是直接把参数对象(TypedParameterValue)的toString结果拼入字符串,生成'%org.hibernate.jpa.TypedParameterValue@d41192d%'
  3. 此时查询条件'%xxx%' IS NULL永远为false,同时name LIKE '%xxx%'也匹配不到任何数据,最终返回空页

修复方案

方案1:使用命名参数+HQL函数拼接通配符

修改HQL,利用Hibernate的CONCAT函数在查询语句中拼接通配符,确保参数被正确绑定:

public interface TestRepository extends JpaRepository<Test, Long> {

    @Query("SELECT t FROM Test t WHERE (:keyword IS NULL OR t.name LIKE CONCAT('%', :keyword, '%'))")
    Page<Test> findAll(@Param("keyword") String keyword, Pageable pageable);
}

这种写法无需在业务代码中拼接字符串,直接传入原始keyword即可:

  • 当keyword为null时,CONCAT('%', null, '%')返回null,条件(:keyword IS NULL OR ...)生效,返回所有数据
  • 当keyword有值时,CONCAT生成正确的模糊匹配字符串,查询正常

方案2:命名参数+业务层拼接通配符

如果偏好在业务层处理字符串拼接,可拆分参数:

public interface TestRepository extends JpaRepository<Test, Long> {

    @Query("SELECT t FROM Test t WHERE (:keyword IS NULL OR t.name LIKE :keywordPattern)")
    Page<Test> findAll(@Param("keyword") String keyword, 
                       @Param("keywordPattern") String keywordPattern, 
                       Pageable pageable);
}

控制器中处理参数:

@GetMapping("/ab")
public Page<Test> ab(CustomPageable pageable) {
    String keyword = pageable.getKeyword();
    String keywordPattern = keyword != null ? "%" + keyword + "%" : null;
    return testRepository.findAll(keyword, keywordPattern, pageable);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 00:15:43