logo

MyBatis模糊查询实战指南:LIKE的规范用法与优化策略

作者:demo2025.09.19 15:53浏览量:18

简介:本文详细解析MyBatis中LIKE模糊查询的规范用法,涵盖参数拼接、SQL注入防护、性能优化等核心场景,提供XML与注解两种实现方式的完整示例。

一、模糊查询的基础语法与安全隐患

MyBatis实现模糊查询的核心是通过SQL的LIKE语句,但直接拼接参数会导致SQL注入风险。典型错误写法如下:

  1. <!-- 错误示范:直接拼接参数 -->
  2. <select id="searchByName" resultType="User">
  3. SELECT * FROM user WHERE name LIKE '%#{name}%'
  4. </select>

这种写法存在两大问题:

  1. 参数未正确转义,#{name}被当作字符串字面量而非参数
  2. 百分号(%)的位置错误导致查询失效

正确的参数传递方式应采用以下三种形式:

1. 参数拼接(推荐XML方式)

  1. <!-- 正确写法1:CONCAT函数拼接 -->
  2. <select id="searchByName" resultType="User">
  3. SELECT * FROM user
  4. WHERE name LIKE CONCAT('%', #{name}, '%')
  5. </select>
  6. <!-- 正确写法2:绑定变量拼接 -->
  7. <select id="searchByName" resultType="User">
  8. SELECT * FROM user
  9. WHERE name LIKE '%' || #{name} || '%' <!-- Oracle/PostgreSQL -->
  10. <!-- MySQL应使用CONCAT,SQL Server使用+号拼接 -->
  11. </select>

2. 注解方式实现

  1. @Select("<script>" +
  2. "SELECT * FROM user " +
  3. "WHERE name LIKE CONCAT('%', #{name}, '%')" +
  4. "</script>")
  5. List<User> searchByName(@Param("name") String name);

3. 动态SQL优化

对于多条件模糊查询,推荐使用<where><if>组合:

  1. <select id="advancedSearch" resultType="User">
  2. SELECT * FROM user
  3. <where>
  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. </where>
  11. </select>

二、性能优化策略

模糊查询的性能瓶颈主要在于全表扫描,优化方案包括:

1. 索引优化

  • 对TEXT/VARCHAR字段建立普通索引
  • 避免在索引列开头使用通配符(如LIKE '%张%'无法使用索引)
  • 考虑使用函数索引(MySQL 8.0+支持):
    1. CREATE INDEX idx_name_fuzzy ON user((name)); -- 前缀索引

2. 分页查询实现

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

3. 数据库方言适配

不同数据库的LIKE实现存在差异:
| 数据库 | 拼接语法 | 注意事项 |
|—————|—————————-|————————————|
| MySQL | CONCAT(‘%’,?,’%’) | 需设置sql_mode=NO_BACKSLASH_ESCAPES |
| Oracle | ‘%’||?||’%’ | 注意NULL值处理 |
| SQL Server| ‘%’+?+’%’ | 使用+号拼接 |
| PostgreSQL| ‘%’||?||’%’ | 推荐使用标准SQL |

三、安全防护机制

1. 参数转义处理

  1. // 自定义TypeHandler处理特殊字符
  2. public class LikeTypeHandler extends BaseTypeHandler<String> {
  3. @Override
  4. public void setNonNullParameter(PreparedStatement ps, int i,
  5. String parameter, JdbcType jdbcType) throws SQLException {
  6. // 转义%_等特殊字符
  7. String safeParam = parameter.replace("%", "\\%")
  8. .replace("_", "\\_");
  9. ps.setString(i, "%" + safeParam + "%");
  10. }
  11. }

2. 预编译语句防护

MyBatis默认使用预编译语句,但需确保:

  • 不使用${}拼接SQL片段
  • 复杂查询使用<script>标签包裹
  • 参数类型与数据库字段严格匹配

四、高级应用场景

1. 多字段模糊查询

  1. <select id="multiFieldSearch" resultType="User">
  2. SELECT * FROM user
  3. WHERE
  4. <foreach item="field" index="index" collection="fields" open="(" separator=" OR " close=")">
  5. ${field} LIKE CONCAT('%', #{keyword}, '%')
  6. </foreach>
  7. </select>

2. 模糊查询计数优化

  1. <select id="countByFuzzyName" resultType="int">
  2. SELECT COUNT(*) FROM (
  3. SELECT 1 FROM user
  4. WHERE name LIKE CONCAT('%', #{name}, '%')
  5. LIMIT 10000 -- 限制扫描行数
  6. ) AS tmp
  7. </select>

3. 全文索引替代方案

对于大规模数据,建议考虑:

五、最佳实践总结

  1. 参数处理原则

    • 始终使用#{}而非${}
    • 百分号应在参数外部处理
    • 复杂查询使用<script>标签
  2. 性能优化路径

    1. graph TD
    2. A[模糊查询] --> B{数据量}
    3. B -->|小于1万| C[普通LIKE]
    4. B -->|大于1万| D[全文索引]
    5. C --> E{是否多条件}
    6. E -->|是| F[动态SQL组合]
    7. E -->|否| G[简单CONCAT]
  3. 安全检查清单

    • 验证所有用户输入
    • 限制查询结果集大小
    • 记录异常查询日志
  4. 跨数据库适配方案

    1. // 数据库方言配置示例
    2. public class DialectConfig {
    3. public static String likeConcat(String column, String param) {
    4. switch (DatabaseType.current()) {
    5. case MYSQL: return column + " LIKE CONCAT('%', ?, '%')";
    6. case ORACLE: return column + " LIKE '%' || ? || '%'";
    7. default: throw new UnsupportedOperationException();
    8. }
    9. }
    10. }

通过系统掌握这些技术要点,开发者可以构建出既安全又高效的MyBatis模糊查询功能。实际应用中,建议结合具体业务场景进行性能测试,持续优化查询策略。

相关文章推荐

发表评论

活动