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

如何在Spring Data JPQL LIKE查询中转义'_'和'%'通配符?

Spring Data JPA LIKE查询中转义通配符(_、%)的解决方案

问题背景

我在Spring Data Repository中定义了如下方法:

@Query("""
    select t from ToneEntity t
    where (:title is null or (t.title like %:title%))
    and (:albumId is null or (t.album.id = :albumId))
    and (:artistId is null or (t.artist.id = :artistId))
    and (:creatorId is null or (t.creator.id = :creatorId))
""")
fun findFilteredTones(
    @Param("title") title: String?,
    @Param("albumId") albumId: Long?,
    @Param("artistId") artistId: Long?,
    @Param("creatorId") creatorId: Long?,
    pageable: Pageable
): List<ToneEntity>

当标题包含_或%字符时,Spring Data会将其作为SQL通配符而非字面量处理。例如数据库中存在标题为bug_with_underscore的ToneEntity,用户在Web UI输入_想要查找包含该字面量的音频,实际却返回了所有音频数据。

使用的Spring Data JPA版本为2.3.5,目前已找到两种可行方案:

  • 使用SQL的concat和replace函数处理参数
  • 在传入查询前手动转义通配符字符

想知道2022年是否有更优的解决方案?目前未找到比使用切面手动转义通配符更好的方法,而这类问题在项目中频繁出现。


针对Spring Data JPA 2.3.5的可行方案

1. JPQL层面直接处理(无额外代码侵入)

修改@Query中的LIKE条件,通过SQL函数对参数进行转义并指定转义字符,确保数据库将特殊字符视为字面量:

@Query("""
    select t from ToneEntity t
    where (:title is null or (t.title like concat('%', replace(replace(:title, '_', '\\_'), '%', '\\%'), '%') escape '\\'))
    and (:albumId is null or (t.album.id = :albumId))
    and (:artistId is null or (t.artist.id = :artistId))
    and (:creatorId is null or (t.creator.id = :creatorId))
""")
fun findFilteredTones(
    @Param("title") title: String?,
    @Param("albumId") albumId: Long?,
    @Param("artistId") artistId: Long?,
    @Param("creatorId") creatorId: Long?,
    pageable: Pageable
): List<ToneEntity>

逻辑说明:先用replace把参数中的_和%转义为\_和\%,再用concat拼接前后的%,最后通过escape '\\'告知数据库转义字符规则。

2. 自定义参数转换器(全局复用)

创建通用的字符串转义转换器,实现Converter<String, String>接口,自动处理通配符:

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@Component
public class LikeWildcardEscapeConverter implements Converter<String, String> {
    @Override
    public String convert(String source) {
        if (source == null) {
            return null;
        }
        // 转义%、_和本身的转义符\,适配多数数据库规则
        return source.replace("\\", "\\\\")
                     .replace("%", "\\%")
                     .replace("_", "\\_");
    }
}

然后在Repository方法的参数上通过@Convert指定转换器:

@Query("""
    select t from ToneEntity t
    where (:title is null or (t.title like concat('%', :title, '%') escape '\\'))
    and (:albumId is null or (t.album.id = :albumId))
    and (:artistId is null or (t.artist.id = :artistId))
    and (:creatorId is null or (t.creator.id = :creatorId))
""")
fun findFilteredTones(
    @Param("title") @Convert(converter = LikeWildcardEscapeConverter::class) title: String?,
    @Param("albumId") albumId: Long?,
    @Param("artistId") artistId: Long?,
    @Param("creatorId") creatorId: Long?,
    pageable: Pageable
): List<ToneEntity>

这种方案可全局复用转换器,避免每个查询重复编写转义逻辑。

3. 切面统一处理(批量解决同类问题)

如果项目中有大量类似的LIKE查询,使用切面可实现零侵入的全局统一转义:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LikeParameterEscapeAspect {

    @Before("execution(* com.yourpackage.repository.*.*(.., String+, ..))")
    public void escapeLikeParameters(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            if (arg instanceof String) {
                String str = (String) arg;
                // 转义通配符,可结合自定义注解(如@EscapeLike)精准匹配需要转义的参数
                String escaped = str.replace("\\", "\\\\")
                                   .replace("%", "\\%")
                                   .replace("_", "\\_");
                args[i] = escaped;
            }
        }
    }
}

注意:需要根据项目实际的Repository包路径调整切点表达式,也可自定义注解标记需要转义的参数,避免误处理非LIKE查询的字符串参数。


关于"更优方案"的说明

在Spring Data JPA 2.3.x版本(包括2022年的版本),框架本身并未提供内置的自动转义LIKE通配符的功能。上述三种方案中:

  • 自定义参数转换器兼顾复用性和代码侵入性,是推荐的常规方案;
  • 切面处理适合批量解决项目中大量同类查询的转义需求,但需注意参数的精准匹配,避免影响其他业务逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:15:34