logo

MyBatis模糊查询:LIKE语句的正确使用与最佳实践

作者:暴富20212025.09.19 15:54浏览量:0

简介:本文详细解析MyBatis中LIKE模糊查询的四种实现方式,结合XML映射与注解开发两种场景,提供防SQL注入方案及性能优化建议。

MyBatis模糊查询:LIKE语句的正确使用与最佳实践

在MyBatis框架中进行数据库模糊查询时,LIKE语句的正确使用直接关系到查询结果的准确性和系统安全性。本文将从基础语法、参数处理、安全防护和性能优化四个维度,系统讲解MyBatis中LIKE查询的最佳实践。

一、基础语法实现方式

1.1 XML映射文件实现

在XML映射文件中,LIKE查询主要有三种写法:

方式一:直接拼接(不推荐)

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

这种方式存在SQL注入风险,当传入的name参数包含恶意SQL片段时,会导致数据库安全问题。

方式二:参数化查询(推荐)

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

或使用数据库特定的连接函数:

  1. <!-- MySQL -->
  2. <select id="findByName" resultType="User">
  3. SELECT * FROM user WHERE name LIKE '%' || #{name} || '%'
  4. </select>
  5. <!-- Oracle -->
  6. <select id="findByName" resultType="User">
  7. SELECT * FROM user WHERE name LIKE '%' || #{name} || '%'
  8. </select>

方式三:动态SQL拼接

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

1.2 注解方式实现

使用@Select注解实现模糊查询:

  1. @Select("SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%')")
  2. List<User> findByName(@Param("name") String name);

二、参数处理技巧

2.1 前后模糊查询

实现”包含”查询(name字段包含参数值):

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

2.2 前缀模糊查询

实现”以…开头”查询:

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

2.3 后缀模糊查询

实现”以…结尾”查询:

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

2.4 多字段模糊查询

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

三、安全防护措施

3.1 防止SQL注入

必须使用#{}参数占位符,避免使用${}直接拼接:

  1. <!-- 安全写法 -->
  2. <select id="safeSearch" resultType="User">
  3. SELECT * FROM user WHERE name LIKE CONCAT('%', #{keyword}, '%')
  4. </select>
  5. <!-- 危险写法 -->
  6. <select id="unsafeSearch" resultType="User">
  7. SELECT * FROM user WHERE name LIKE '%${keyword}%'
  8. </select>

3.2 参数校验

在Service层进行参数校验:

  1. public List<User> searchUsers(String keyword) {
  2. if (keyword == null || keyword.trim().isEmpty()) {
  3. throw new IllegalArgumentException("搜索关键词不能为空");
  4. }
  5. // 去除特殊字符
  6. String safeKeyword = keyword.replaceAll("[';\\-]", "");
  7. return userMapper.findByName(safeKeyword);
  8. }

3.3 最小权限原则

数据库用户应只拥有必要的查询权限,避免使用具有DDL权限的高权限账户。

四、性能优化建议

4.1 索引优化

对LIKE查询字段建立合适的索引:

  1. -- 创建函数索引(MySQL 8.0+)
  2. CREATE INDEX idx_user_name ON user((name));
  3. -- 或使用反向索引(适用于后缀查询)
  4. CREATE INDEX idx_user_name_reverse ON user(REVERSE(name));

4.2 查询条件优化

避免在索引列上使用前导通配符:

  1. <!-- 不推荐:无法使用索引 -->
  2. <select id="findByNameStart" resultType="User">
  3. SELECT * FROM user WHERE name LIKE '%张'
  4. </select>
  5. <!-- 推荐:可以使用索引 -->
  6. <select id="findByNameEnd" resultType="User">
  7. SELECT * FROM user WHERE name LIKE '张%'
  8. </select>

4.3 分页处理

大数据量时必须实现分页:

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

4.4 缓存策略

对频繁执行的模糊查询考虑使用二级缓存:

  1. <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

五、常见问题解决方案

5.1 特殊字符处理

当搜索词包含%_时:

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

5.2 空值处理

  1. <select id="findByNameOptional" resultType="User">
  2. SELECT * FROM user
  3. <where>
  4. <if test="name != null and name != ''">
  5. name LIKE CONCAT('%', #{name}, '%')
  6. </if>
  7. </where>
  8. </select>

5.3 多数据库兼容

使用MyBatis的动态SQL处理不同数据库的语法差异:

  1. <select id="findByName" resultType="User">
  2. SELECT * FROM user WHERE name LIKE
  3. <choose>
  4. <when test="_databaseId == 'mysql'">
  5. CONCAT('%', #{name}, '%')
  6. </when>
  7. <when test="_databaseId == 'oracle'">
  8. '%' || #{name} || '%'
  9. </when>
  10. <otherwise>
  11. '%' + #{name} + '%'
  12. </otherwise>
  13. </choose>
  14. </select>

六、最佳实践总结

  1. 始终使用参数化查询:坚持使用#{}占位符,杜绝SQL注入风险
  2. 合理设计索引:根据查询模式设计适当的索引
  3. 实现分页机制:避免大数据量查询导致性能问题
  4. 进行参数校验:在Service层验证输入参数
  5. 考虑数据库兼容:处理不同数据库的语法差异
  6. 优化查询条件:避免在索引列上使用前导通配符

通过遵循这些最佳实践,开发者可以在MyBatis中安全、高效地实现模糊查询功能,既保证系统安全性,又提升查询性能。在实际开发中,建议结合具体业务场景选择最适合的实现方式,并通过性能测试验证优化效果。

相关文章推荐

发表评论