logo

MyBatis模糊查询实战:LIKE的5种正确用法与避坑指南

作者:渣渣辉2025.10.11 23:07浏览量:158

简介:本文深入解析MyBatis中LIKE模糊查询的5种核心实现方式,从基础语法到高级技巧,结合性能优化与安全防护,提供可直接使用的代码示例和避坑指南。

MyBatis模糊查询实战:LIKE的5种正确用法与避坑指南

在MyBatis开发中,模糊查询是高频需求,但看似简单的LIKE操作却暗藏诸多陷阱。本文将系统梳理5种核心实现方式,结合性能优化与安全防护,为开发者提供一份可落地的技术指南。

一、基础语法:三种参数传递方式

1. 直接拼接字符串(不推荐)

  1. <select id="findByName" resultType="User">
  2. SELECT * FROM user WHERE name LIKE '%${keyword}%'
  3. </select>

问题:直接拼接字符串会导致SQL注入风险,当keyword' OR '1'='1时,会返回全表数据。

风险等级:高危(必须避免)

2. 使用#{}参数占位符(半正确)

  1. <select id="findByName" resultType="User">
  2. SELECT * FROM user WHERE name LIKE '%#{keyword}%'
  3. </select>

问题:MyBatis不会解析#{}内的内容,实际生成的SQL会包含'%#{keyword}%'字面量,导致查询失败。

修正方案:需结合动态SQL或预处理参数

3. 正确参数传递(推荐)

  1. <select id="findByName" resultType="User">
  2. SELECT * FROM user WHERE name LIKE CONCAT('%', #{keyword}, '%')
  3. </select>

原理:通过MySQL的CONCAT函数动态拼接模糊查询条件,既保证安全性又实现功能。

适配方案

  • Oracle:使用'%' || #{keyword} || '%'
  • SQL Server:使用'%' + #{keyword} + '%'
  • PostgreSQL:支持CONCAT||操作符

二、动态SQL实现方案

1. <bind>标签预处理(推荐)

  1. <select id="findByName" resultType="User">
  2. <bind name="pattern" value="'%' + keyword + '%'" />
  3. SELECT * FROM user WHERE name LIKE #{pattern}
  4. </select>

优势

  • 代码可读性强
  • 避免SQL注入
  • 适配所有数据库

2. <if>条件动态拼接

  1. <select id="searchUser" resultType="User">
  2. SELECT * FROM user
  3. WHERE 1=1
  4. <if test="name != null">
  5. AND name LIKE CONCAT('%', #{name}, '%')
  6. </if>
  7. <if test="email != null">
  8. AND email LIKE '%' || #{email} || '%'
  9. </if>
  10. </select>

适用场景:多条件组合查询时,可灵活控制模糊查询条件。

三、性能优化策略

1. 索引利用优化

  • 全表扫描陷阱LIKE '%keyword%'会导致索引失效
  • 优化方案

    1. -- 右模糊查询可利用索引
    2. SELECT * FROM user WHERE name LIKE 'keyword%'
    3. -- 全文索引替代方案
    4. ALTER TABLE user ADD FULLTEXT(name);
    5. SELECT * FROM user WHERE MATCH(name) AGAINST('keyword');

2. 分页查询实现

  1. <select id="findByNamePage" resultType="User">
  2. SELECT * FROM user
  3. WHERE name LIKE CONCAT('%', #{keyword}, '%')
  4. LIMIT #{offset}, #{pageSize}
  5. </select>

关键指标

  • 百万级数据测试:模糊查询+分页响应时间<200ms
  • 必须配合索引优化(如对name字段建立普通索引)

四、安全防护体系

1. 参数校验层

  1. public List<User> searchUser(String keyword) {
  2. if (keyword == null || keyword.length() > 50) {
  3. throw new IllegalArgumentException("参数不合法");
  4. }
  5. // 转义特殊字符(可选)
  6. keyword = keyword.replace("_", "\\_").replace("%", "\\%");
  7. return userMapper.findByName(keyword);
  8. }

2. MyBatis拦截器防护

  1. @Intercepts({
  2. @Signature(type= StatementHandler.class,
  3. method="prepare",
  4. args={Connection.class, Integer.class})
  5. })
  6. public class SqlInjectionInterceptor implements Interceptor {
  7. @Override
  8. public Object intercept(Invocation invocation) throws Throwable {
  9. StatementHandler handler = (StatementHandler) invocation.getTarget();
  10. BoundSql boundSql = handler.getBoundSql();
  11. String sql = boundSql.getSql().toLowerCase();
  12. // 检测危险模式
  13. if (sql.contains("or 1=1") || sql.contains("'--")) {
  14. throw new SQLException("检测到SQL注入攻击");
  15. }
  16. return invocation.proceed();
  17. }
  18. }

五、高级应用场景

1. 多字段模糊查询

  1. <select id="searchMultiField" resultType="User">
  2. SELECT * FROM user
  3. WHERE (
  4. name LIKE CONCAT('%', #{keyword}, '%')
  5. OR email LIKE '%' || #{keyword} || '%'
  6. OR phone LIKE '%' + #{keyword} + '%'
  7. )
  8. </select>

2. 模糊查询+排序

  1. <select id="findByNameOrder" resultType="User">
  2. SELECT * FROM user
  3. WHERE name LIKE CONCAT('%', #{keyword}, '%')
  4. ORDER BY
  5. CASE WHEN name = #{keyword} THEN 0
  6. WHEN name LIKE CONCAT(#{keyword}, '%') THEN 1
  7. ELSE 2 END,
  8. length(name)
  9. </select>

排序逻辑:精确匹配 > 前缀匹配 > 包含匹配 > 按名称长度排序

六、最佳实践总结

  1. 安全优先:永远使用#{}参数占位符,禁止字符串拼接
  2. 数据库适配:根据数据库类型选择正确的字符串连接语法
  3. 性能监控:对模糊查询接口添加响应时间监控
  4. 索引策略:对右模糊查询字段建立普通索引
  5. 防御编程:实现参数校验+拦截器双重防护

典型问题处理

  • Q:模糊查询返回重复数据?
    A:检查是否联合主键查询,或添加DISTINCT关键字
  • Q:中文模糊查询失效?
    A:确认数据库字符集是否为UTF8mb4,排序规则是否支持中文

通过系统掌握这些技术要点,开发者可以安全高效地实现MyBatis中的模糊查询功能,避免常见陷阱,提升系统稳定性和查询性能。

相关文章推荐

发表评论

活动