MyBatis模糊查询实战指南:LIKE的规范用法与优化策略
2025.09.19 15:53浏览量:18简介:本文详细解析MyBatis中LIKE模糊查询的规范用法,涵盖参数拼接、SQL注入防护、性能优化等核心场景,提供XML与注解两种实现方式的完整示例。
一、模糊查询的基础语法与安全隐患
MyBatis实现模糊查询的核心是通过SQL的LIKE语句,但直接拼接参数会导致SQL注入风险。典型错误写法如下:
<!-- 错误示范:直接拼接参数 --><select id="searchByName" resultType="User">SELECT * FROM user WHERE name LIKE '%#{name}%'</select>
这种写法存在两大问题:
- 参数未正确转义,
#{name}被当作字符串字面量而非参数 - 百分号(%)的位置错误导致查询失效
正确的参数传递方式应采用以下三种形式:
1. 参数拼接(推荐XML方式)
<!-- 正确写法1:CONCAT函数拼接 --><select id="searchByName" resultType="User">SELECT * FROM userWHERE name LIKE CONCAT('%', #{name}, '%')</select><!-- 正确写法2:绑定变量拼接 --><select id="searchByName" resultType="User">SELECT * FROM userWHERE name LIKE '%' || #{name} || '%' <!-- Oracle/PostgreSQL --><!-- MySQL应使用CONCAT,SQL Server使用+号拼接 --></select>
2. 注解方式实现
@Select("<script>" +"SELECT * FROM user " +"WHERE name LIKE CONCAT('%', #{name}, '%')" +"</script>")List<User> searchByName(@Param("name") String name);
3. 动态SQL优化
对于多条件模糊查询,推荐使用<where>和<if>组合:
<select id="advancedSearch" resultType="User">SELECT * FROM user<where><if test="name != null">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="email != null">AND email LIKE '%' || #{email} || '%'</if></where></select>
二、性能优化策略
模糊查询的性能瓶颈主要在于全表扫描,优化方案包括:
1. 索引优化
- 对TEXT/VARCHAR字段建立普通索引
- 避免在索引列开头使用通配符(如
LIKE '%张%'无法使用索引) - 考虑使用函数索引(MySQL 8.0+支持):
CREATE INDEX idx_name_fuzzy ON user((name)); -- 前缀索引
2. 分页查询实现
<select id="searchWithPagination" resultType="User">SELECT * FROM userWHERE name LIKE CONCAT('%', #{name}, '%')LIMIT #{offset}, #{pageSize}</select>
3. 数据库方言适配
不同数据库的LIKE实现存在差异:
| 数据库 | 拼接语法 | 注意事项 |
|—————|—————————-|————————————|
| MySQL | CONCAT(‘%’,?,’%’) | 需设置sql_mode=NO_BACKSLASH_ESCAPES |
| Oracle | ‘%’||?||’%’ | 注意NULL值处理 |
| SQL Server| ‘%’+?+’%’ | 使用+号拼接 |
| PostgreSQL| ‘%’||?||’%’ | 推荐使用标准SQL |
三、安全防护机制
1. 参数转义处理
// 自定义TypeHandler处理特殊字符public class LikeTypeHandler extends BaseTypeHandler<String> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i,String parameter, JdbcType jdbcType) throws SQLException {// 转义%_等特殊字符String safeParam = parameter.replace("%", "\\%").replace("_", "\\_");ps.setString(i, "%" + safeParam + "%");}}
2. 预编译语句防护
MyBatis默认使用预编译语句,但需确保:
- 不使用
${}拼接SQL片段 - 复杂查询使用
<script>标签包裹 - 参数类型与数据库字段严格匹配
四、高级应用场景
1. 多字段模糊查询
<select id="multiFieldSearch" resultType="User">SELECT * FROM userWHERE<foreach item="field" index="index" collection="fields" open="(" separator=" OR " close=")">${field} LIKE CONCAT('%', #{keyword}, '%')</foreach></select>
2. 模糊查询计数优化
<select id="countByFuzzyName" resultType="int">SELECT COUNT(*) FROM (SELECT 1 FROM userWHERE name LIKE CONCAT('%', #{name}, '%')LIMIT 10000 -- 限制扫描行数) AS tmp</select>
3. 全文索引替代方案
对于大规模数据,建议考虑:
- MySQL的FULLTEXT索引
- Elasticsearch等搜索引擎
- Redis的Search模块
五、最佳实践总结
参数处理原则:
- 始终使用
#{}而非${} - 百分号应在参数外部处理
- 复杂查询使用
<script>标签
- 始终使用
性能优化路径:
graph TDA[模糊查询] --> B{数据量}B -->|小于1万| C[普通LIKE]B -->|大于1万| D[全文索引]C --> E{是否多条件}E -->|是| F[动态SQL组合]E -->|否| G[简单CONCAT]
安全检查清单:
- 验证所有用户输入
- 限制查询结果集大小
- 记录异常查询日志
跨数据库适配方案:
// 数据库方言配置示例public class DialectConfig {public static String likeConcat(String column, String param) {switch (DatabaseType.current()) {case MYSQL: return column + " LIKE CONCAT('%', ?, '%')";case ORACLE: return column + " LIKE '%' || ? || '%'";default: throw new UnsupportedOperationException();}}}
通过系统掌握这些技术要点,开发者可以构建出既安全又高效的MyBatis模糊查询功能。实际应用中,建议结合具体业务场景进行性能测试,持续优化查询策略。

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