在数据库操作中,模糊查询是一种常见的查询方式,它允许用户通过部分匹配获取符合条件的数据,例如搜索用户名、商品名称等场景,在Java开发中,实现模糊查询需要结合SQL语法和Java代码逻辑,同时兼顾性能与安全性,本文将详细介绍Java中模糊查询的实现方法、优化技巧及注意事项。

SQL层面的模糊查询基础
模糊查询的核心是SQL中的LIKE操作符,配合通配符实现灵活匹配,通配符主要包括两种:(匹配任意数量的任意字符,包括0个)和_(匹配单个任意字符)。SELECT * FROM users WHERE username LIKE '张%'会查询所有以“张”开头的用户,而LIKE '%张%'则查询包含“张”的用户,LIKE '张_'匹配“张”加任意一个字符的用户。
不同数据库对LIKE的支持略有差异,MySQL、PostgreSQL等主流数据库均支持标准LIKE语法,Oracle数据库中还可使用REGEXP_LIKE实现正则表达式模糊匹配,例如REGEXP_LIKE(username, '^张.*')等同于LIKE '张%',需要注意的是,LIKE对大小写敏感的数据库(如Oracle默认区分大小写)可能需要使用LOWER或UPPER函数统一大小写,例如WHERE LOWER(username) LIKE LOWER('%zhang%')。
Java代码中的模糊查询实现
在Java中,模糊查询通常通过JDBC或ORM框架(如MyBatis、Hibernate)实现,关键在于安全地拼接SQL条件并避免SQL注入。
基于JDBC的实现
使用JDBC时,推荐通过PreparedStatement的占位符传递模糊查询参数,而非直接拼接SQL字符串。
String keyword = "张";
String sql = "SELECT * FROM users WHERE username LIKE ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "%" + keyword + "%"); // 设置模糊查询参数
ResultSet rs = ps.executeQuery();
// 处理结果集
}
这种方式通过预编译SQL,确保参数值被当作数据处理,避免SQL注入风险。
基于MyBatis的实现
MyBatis提供了更灵活的动态SQL支持,可通过XML映射文件或注解实现模糊查询,在XML中,使用<if>标签动态拼接条件:

<select id="findByUsername" resultType="User">
SELECT * FROM users
<where>
<if test="username != null">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
</where>
</select>
注解方式可直接使用@Select:
@Select("SELECT * FROM users WHERE username LIKE CONCAT('%', #{keyword}, '%')")
List<User> findByKeyword(@Param("keyword") String keyword);
MyBatis的CONCAT函数可避免手动拼接字符串导致的语法错误,同时保持代码可读性。
模糊查询的性能优化
模糊查询(尤其是前导通配符%abc)会导致数据库无法使用索引,全表扫描性能极差,针对大表数据,需从以下方面优化:
避免前导通配符
优先使用后缀匹配(如abc%),可通过索引加速查询,搜索以“张”开头的用户时,LIKE '张%'可利用索引,而LIKE '%张%'无法使用索引,若必须使用中间或后置通配符,可考虑全文索引(MySQL的FULLTEXT索引、PostgreSQL的tsvector),适用于文本内容搜索(如文章、评论)。
使用搜索引擎
对复杂模糊查询(如多字段、分词匹配),可引入Elasticsearch、Solr等搜索引擎,它们基于倒排索引,支持高效模糊查询、分词搜索和聚合分析,适合海量数据场景,将用户数据同步到Elasticsearch后,可通过match查询实现模糊匹配:
SearchRequest request = new SearchRequest("users");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery("username", "张"));
request.source(sourceBuilder);
限制查询范围
通过分页(LIMIT、OFFSET)或时间范围、分类等条件缩小查询数据量,避免全表扫描,先按用户注册时间筛选,再进行模糊查询。

安全注意事项
模糊查询需重点防范SQL注入风险。禁止直接拼接SQL字符串,例如以下危险代码:
String keyword = request.getParameter("keyword");
String sql = "SELECT * FROM users WHERE username LIKE '%" + keyword + "%'"; // 易被注入
攻击者可输入' OR '1'='1,使SQL变为SELECT * FROM users WHERE username LIKE '%' OR '1'='1'%',导致返回所有数据,正确做法是使用PreparedStatement或ORM框架的参数化查询,如前文JDBC和MyBatis示例。
多条件模糊查询与动态SQL
实际业务中,模糊查询常涉及多字段组合(如用户名、邮箱、手机号),可通过动态SQL灵活拼接条件,例如MyBatis的<where>和<if>标签:
<select id="findByCondition" resultType="User">
SELECT * FROM users
<where>
<if test="username != null">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="email != null">
AND email LIKE CONCAT('%', #{email}, '%')
</if>
<if test="phone != null">
AND phone LIKE CONCAT('%', #{phone}, '%')
</if>
</where>
LIMIT #{offset}, #{pageSize}
</select>
Spring Data JPA可通过Specification接口实现动态条件查询,
public Specification<User> findByKeyword(String keyword) {
return (root, query, cb) -> {
if (StringUtils.isEmpty(keyword)) {
return cb.conjunction();
}
return cb.or(
cb.like(root.get("username"), "%" + keyword + "%"),
cb.like(root.get("email"), "%" + keyword + "%")
);
};
}
Java中的模糊查询需结合SQL语法和代码逻辑实现,核心是使用LIKE操作符和通配符,并通过PreparedStatement或ORM框架确保安全性,针对性能问题,应避免前导通配符、合理使用索引,或引入搜索引擎处理海量数据,多条件查询可通过动态SQL灵活实现,满足复杂业务需求,实际开发中,需根据数据量、查询场景选择合适方案,平衡性能与安全性。
















