Hibernate执行HQL查询报错QuerySyntaxException:ILIKE语法问题
问题分析
HQL是Hibernate为跨数据库兼容设计的查询语言,并不原生支持PostgreSQL特有的ILIKE和ANY(ARRAY[])语法——这就是你触发QuerySyntaxException的核心原因。而Adminer直接执行的是原生PostgreSQL SQL,所以能正常运行。
解决方案
根据你的场景需求,可以选择以下几种处理方式:
1. 直接使用原生SQL查询
这是最直接的方案,绕过HQL的语法限制,直接执行PostgreSQL原生语句:
String sql = "SELECT * FROM your_table WHERE your_column ILIKE ANY(ARRAY[:keywords])"; Query query = entityManager.createNativeQuery(sql, YourEntity.class); query.setParameter("keywords", new String[]{"%foo%", "%bar%"}); List<YourEntity> results = query.getResultList();
2. 用HQL模拟ILIKE效果(跨数据库友好)
如果需要保留HQL的跨数据库特性,可以通过upper()函数把字段和参数统一转成大写,再用普通like实现不区分大小写匹配:
List<String> keywords = Arrays.asList("%FOO%", "%BAR%"); String hql = "FROM YourEntity e WHERE upper(e.yourColumn) IN (:keywords)"; Query query = session.createQuery(hql, YourEntity.class); query.setParameter("keywords", keywords.stream().map(String::toUpperCase).collect(Collectors.toList())); List<YourEntity> results = query.getResultList();
注意:如果关键词带通配符,IN无法实现模糊匹配,此时需要用OR连接多个like条件,或者参考下面的自定义函数方案。
3. 自定义HQL函数支持ILIKE ANY
通过扩展Hibernate的函数注册,让HQL直接支持PostgreSQL的ILIKE ANY语法:
- 首先在Spring Boot配置文件中指定自定义方言函数注册器:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.query.registrar.postgresql=your.package.CustomPostgreSQLFunctionRegistrar
- 实现函数注册器:
public class CustomPostgreSQLFunctionRegistrar implements FunctionContributor { @Override public void contributeFunctions(FunctionContributions functionContributions) { functionContributions.getFunctionRegistry().register( "ilike_any", new SQLFunctionTemplate(StandardBasicTypes.BOOLEAN, "?1 ILIKE ANY(?2)") ); } }
- 之后即可在HQL中使用自定义函数:
String hql = "FROM YourEntity e WHERE ilike_any(e.yourColumn, :keywords)"; Query query = session.createQuery(hql, YourEntity.class); query.setParameter("keywords", new String[]{"%foo%", "%bar%"}); List<YourEntity> results = query.getResultList();
4. 用Criteria API构建查询
如果偏好类型安全的查询方式,用Criteria API通过OR连接多个模糊匹配条件,模拟ILIKE ANY的效果:
CriteriaBuilder cb = session.getCriteriaBuilder(); CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class); Root<YourEntity> root = cq.from(YourEntity.class); List<String> keywords = Arrays.asList("%foo%", "%bar%"); Predicate[] predicates = keywords.stream() .map(keyword -> cb.like(cb.upper(root.get("yourColumn")), keyword.toUpperCase())) .toArray(Predicate[]::new); cq.where(cb.or(predicates)); List<YourEntity> results = session.createQuery(cq).getResultList();
内容的提问来源于stack exchange,提问作者yesIamFaded
相关产品推荐
相关产品推荐

