MyBatis模糊查询需处理_、%、等特殊字符的转义问题:可通过ESCAPE子句配合手动转义、改用LOCATE/INSTR/POSITION等无通配符函数、自定义拦截器统一处理,或前后端协同过滤实现安全匹配。

MyBatis 模糊查询中遇到 _、%、 等特殊字符时,会把它们当作通配符处理,导致查不到真实含这些字符的数据。比如用户搜“100%合格”,用 LIKE '%100%合格%' 实际匹配的是“任意开头 + 任意字符 + 合格 + 任意结尾”,根本不会命中字段里真正存着“100%合格”的记录。解决核心是:让数据库把特殊字符当普通文本,而不是通配符。
用 ESCAPE 显式声明转义符
在 SQL 中给 LIKE 加 ESCAPE 子句,指定一个转义字符(如 /),再对特殊字符前加该字符即可。MyBatis XML 写法示例:
WHERE name LIKE CONCAT('%', #{keyword}, '%') ESCAPE '/'- Java 传参前手动转义:
keyword.replace("%", "/%").replace("_", "/_").replace("\", "\\"); - 注意:ESCAPE 必须写在 LIKE 表达式之后、整个 WHERE 条件之前,且数据库需支持(MySQL、Oracle 都支持)
改用非 LIKE 的模糊函数
绕开 LIKE 本身,用字符串定位函数实现“包含”语义,天然不识别通配符:
-
LOCATE(#{keyword}, column) > 0—— MySQL,返回位置大于 0 即存在 -
INSTR(column, #{keyword}) > 0—— 功能同 LOCATE,参数顺序相反 -
POSITION(#{keyword} IN column) > 0—— 标准 SQL 写法,兼容性更好 - 优点:无需转义、无通配符干扰;缺点:无法利用索引,大数据量时性能略低
自定义拦截器统一处理
适合中大型项目,避免每个 mapper 都手动处理。通过 MyBatis 拦截器扫描所有查询,自动识别 LIKE 条件并转义参数中的特殊字符:
- 监听
Executor.query方法,解析 BoundSql 获取原始 SQL 和参数 - 匹配 SQL 中是否含
LIKE关键字,并检查对应参数值是否含%、_、 - 对匹配到的参数值做预处理,例如:
value.replaceAll("([%_\\])", "\\$1") - 配合
ESCAPE '\'或使用CONCAT拼接,确保最终 SQL 安全执行
前端+后端协同过滤
简单场景下可从前端输入环节就控制,降低后端负担:
- 表单提交前 JS 替换:
input.replace(/([%_\])/g, '\$1'),再发请求 - 后端接收后二次校验,对疑似恶意或含特殊字符的关键词打日志并告警
- 搭配 MyBatis 的
#{}占位符(非${}!),杜绝 SQL 注入风险


















