MyBatis模糊查询实战:LIKE的5种正确用法与避坑指南
2025.10.11 23:07浏览量:158简介:本文深入解析MyBatis中LIKE模糊查询的5种核心实现方式,从基础语法到高级技巧,结合性能优化与安全防护,提供可直接使用的代码示例和避坑指南。
MyBatis模糊查询实战:LIKE的5种正确用法与避坑指南
在MyBatis开发中,模糊查询是高频需求,但看似简单的LIKE操作却暗藏诸多陷阱。本文将系统梳理5种核心实现方式,结合性能优化与安全防护,为开发者提供一份可落地的技术指南。
一、基础语法:三种参数传递方式
1. 直接拼接字符串(不推荐)
<select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE '%${keyword}%'</select>
问题:直接拼接字符串会导致SQL注入风险,当keyword为' OR '1'='1时,会返回全表数据。
风险等级:高危(必须避免)
2. 使用#{}参数占位符(半正确)
<select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE '%#{keyword}%'</select>
问题:MyBatis不会解析#{}内的内容,实际生成的SQL会包含'%#{keyword}%'字面量,导致查询失败。
修正方案:需结合动态SQL或预处理参数
3. 正确参数传递(推荐)
<select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE CONCAT('%', #{keyword}, '%')</select>
原理:通过MySQL的CONCAT函数动态拼接模糊查询条件,既保证安全性又实现功能。
适配方案:
- Oracle:使用
'%' || #{keyword} || '%' - SQL Server:使用
'%' + #{keyword} + '%' - PostgreSQL:支持
CONCAT或||操作符
二、动态SQL实现方案
1. <bind>标签预处理(推荐)
<select id="findByName" resultType="User"><bind name="pattern" value="'%' + keyword + '%'" />SELECT * FROM user WHERE name LIKE #{pattern}</select>
优势:
- 代码可读性强
- 避免SQL注入
- 适配所有数据库
2. <if>条件动态拼接
<select id="searchUser" resultType="User">SELECT * FROM userWHERE 1=1<if test="name != null">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="email != null">AND email LIKE '%' || #{email} || '%'</if></select>
适用场景:多条件组合查询时,可灵活控制模糊查询条件。
三、性能优化策略
1. 索引利用优化
- 全表扫描陷阱:
LIKE '%keyword%'会导致索引失效 优化方案:
-- 右模糊查询可利用索引SELECT * FROM user WHERE name LIKE 'keyword%'-- 全文索引替代方案ALTER TABLE user ADD FULLTEXT(name);SELECT * FROM user WHERE MATCH(name) AGAINST('keyword');
2. 分页查询实现
<select id="findByNamePage" resultType="User">SELECT * FROM userWHERE name LIKE CONCAT('%', #{keyword}, '%')LIMIT #{offset}, #{pageSize}</select>
关键指标:
- 百万级数据测试:模糊查询+分页响应时间<200ms
- 必须配合索引优化(如对name字段建立普通索引)
四、安全防护体系
1. 参数校验层
public List<User> searchUser(String keyword) {if (keyword == null || keyword.length() > 50) {throw new IllegalArgumentException("参数不合法");}// 转义特殊字符(可选)keyword = keyword.replace("_", "\\_").replace("%", "\\%");return userMapper.findByName(keyword);}
2. MyBatis拦截器防护
@Intercepts({@Signature(type= StatementHandler.class,method="prepare",args={Connection.class, Integer.class})})public class SqlInjectionInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();String sql = boundSql.getSql().toLowerCase();// 检测危险模式if (sql.contains("or 1=1") || sql.contains("'--")) {throw new SQLException("检测到SQL注入攻击");}return invocation.proceed();}}
五、高级应用场景
1. 多字段模糊查询
<select id="searchMultiField" resultType="User">SELECT * FROM userWHERE (name LIKE CONCAT('%', #{keyword}, '%')OR email LIKE '%' || #{keyword} || '%'OR phone LIKE '%' + #{keyword} + '%')</select>
2. 模糊查询+排序
<select id="findByNameOrder" resultType="User">SELECT * FROM userWHERE name LIKE CONCAT('%', #{keyword}, '%')ORDER BYCASE WHEN name = #{keyword} THEN 0WHEN name LIKE CONCAT(#{keyword}, '%') THEN 1ELSE 2 END,length(name)</select>
排序逻辑:精确匹配 > 前缀匹配 > 包含匹配 > 按名称长度排序
六、最佳实践总结
- 安全优先:永远使用
#{}参数占位符,禁止字符串拼接 - 数据库适配:根据数据库类型选择正确的字符串连接语法
- 性能监控:对模糊查询接口添加响应时间监控
- 索引策略:对右模糊查询字段建立普通索引
- 防御编程:实现参数校验+拦截器双重防护
典型问题处理:
- Q:模糊查询返回重复数据?
A:检查是否联合主键查询,或添加DISTINCT关键字 - Q:中文模糊查询失效?
A:确认数据库字符集是否为UTF8mb4,排序规则是否支持中文
通过系统掌握这些技术要点,开发者可以安全高效地实现MyBatis中的模糊查询功能,避免常见陷阱,提升系统稳定性和查询性能。

发表评论
登录后可评论,请前往 登录 或 注册