MyBatis模糊查询:LIKE语句的正确使用与最佳实践
2025.09.19 15:54浏览量:3简介:本文详细解析MyBatis中LIKE模糊查询的四种实现方式,结合XML映射与注解开发两种场景,提供防SQL注入方案及性能优化建议。
MyBatis模糊查询:LIKE语句的正确使用与最佳实践
在MyBatis框架中进行数据库模糊查询时,LIKE语句的正确使用直接关系到查询结果的准确性和系统安全性。本文将从基础语法、参数处理、安全防护和性能优化四个维度,系统讲解MyBatis中LIKE查询的最佳实践。
一、基础语法实现方式
1.1 XML映射文件实现
在XML映射文件中,LIKE查询主要有三种写法:
方式一:直接拼接(不推荐)
<select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE '%${name}%'</select>
这种方式存在SQL注入风险,当传入的name参数包含恶意SQL片段时,会导致数据库安全问题。
方式二:参数化查询(推荐)
<select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%')</select>
或使用数据库特定的连接函数:
<!-- MySQL --><select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE '%' || #{name} || '%'</select><!-- Oracle --><select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE '%' || #{name} || '%'</select>
方式三:动态SQL拼接
<select id="findByName" resultType="User">SELECT * FROM user<where><if test="name != null">name LIKE CONCAT('%', #{name}, '%')</if></where></select>
1.2 注解方式实现
使用@Select注解实现模糊查询:
@Select("SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%')")List<User> findByName(@Param("name") String name);
二、参数处理技巧
2.1 前后模糊查询
实现”包含”查询(name字段包含参数值):
<select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%')</select>
2.2 前缀模糊查询
实现”以…开头”查询:
<select id="findByPrefix" resultType="User">SELECT * FROM user WHERE name LIKE CONCAT(#{name}, '%')</select>
2.3 后缀模糊查询
实现”以…结尾”查询:
<select id="findBySuffix" resultType="User">SELECT * FROM user WHERE name LIKE CONCAT('%', #{name})</select>
2.4 多字段模糊查询
<select id="findByMultiCondition" resultType="User">SELECT * FROM userWHERE name LIKE CONCAT('%', #{name}, '%')OR phone LIKE CONCAT('%', #{phone}, '%')</select>
三、安全防护措施
3.1 防止SQL注入
必须使用#{}参数占位符,避免使用${}直接拼接:
<!-- 安全写法 --><select id="safeSearch" resultType="User">SELECT * FROM user WHERE name LIKE CONCAT('%', #{keyword}, '%')</select><!-- 危险写法 --><select id="unsafeSearch" resultType="User">SELECT * FROM user WHERE name LIKE '%${keyword}%'</select>
3.2 参数校验
在Service层进行参数校验:
public List<User> searchUsers(String keyword) {if (keyword == null || keyword.trim().isEmpty()) {throw new IllegalArgumentException("搜索关键词不能为空");}// 去除特殊字符String safeKeyword = keyword.replaceAll("[';\\-]", "");return userMapper.findByName(safeKeyword);}
3.3 最小权限原则
数据库用户应只拥有必要的查询权限,避免使用具有DDL权限的高权限账户。
四、性能优化建议
4.1 索引优化
对LIKE查询字段建立合适的索引:
-- 创建函数索引(MySQL 8.0+)CREATE INDEX idx_user_name ON user((name));-- 或使用反向索引(适用于后缀查询)CREATE INDEX idx_user_name_reverse ON user(REVERSE(name));
4.2 查询条件优化
避免在索引列上使用前导通配符:
<!-- 不推荐:无法使用索引 --><select id="findByNameStart" resultType="User">SELECT * FROM user WHERE name LIKE '%张'</select><!-- 推荐:可以使用索引 --><select id="findByNameEnd" resultType="User">SELECT * FROM user WHERE name LIKE '张%'</select>
4.3 分页处理
大数据量时必须实现分页:
<select id="findByNamePage" resultType="User">SELECT * FROM userWHERE name LIKE CONCAT('%', #{name}, '%')LIMIT #{offset}, #{pageSize}</select>
4.4 缓存策略
对频繁执行的模糊查询考虑使用二级缓存:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
五、常见问题解决方案
5.1 特殊字符处理
当搜索词包含%或_时:
<select id="findBySpecialChar" resultType="User">SELECT * FROM userWHERE name LIKE CONCAT('%', REPLACE(REPLACE(#{name}, '\\', '\\\\'), '%', '\\%'), '%') ESCAPE '\\'</select>
5.2 空值处理
<select id="findByNameOptional" resultType="User">SELECT * FROM user<where><if test="name != null and name != ''">name LIKE CONCAT('%', #{name}, '%')</if></where></select>
5.3 多数据库兼容
使用MyBatis的动态SQL处理不同数据库的语法差异:
<select id="findByName" resultType="User">SELECT * FROM user WHERE name LIKE<choose><when test="_databaseId == 'mysql'">CONCAT('%', #{name}, '%')</when><when test="_databaseId == 'oracle'">'%' || #{name} || '%'</when><otherwise>'%' + #{name} + '%'</otherwise></choose></select>
六、最佳实践总结
- 始终使用参数化查询:坚持使用
#{}占位符,杜绝SQL注入风险 - 合理设计索引:根据查询模式设计适当的索引
- 实现分页机制:避免大数据量查询导致性能问题
- 进行参数校验:在Service层验证输入参数
- 考虑数据库兼容:处理不同数据库的语法差异
- 优化查询条件:避免在索引列上使用前导通配符
通过遵循这些最佳实践,开发者可以在MyBatis中安全、高效地实现模糊查询功能,既保证系统安全性,又提升查询性能。在实际开发中,建议结合具体业务场景选择最适合的实现方式,并通过性能测试验证优化效果。

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