SpringBoot+Mybatis+Mysql模糊查询实战指南
2025.09.19 15:54浏览量:0简介:本文详细讲解SpringBoot结合Mybatis实现Mysql模糊查询的完整方案,包含技术原理、代码实现及性能优化建议,助力开发者高效构建搜索功能。
SpringBoot+Mybatis+Mysql模糊查询实战指南
一、技术架构与核心原理
在Java企业级开发中,SpringBoot+Mybatis+Mysql的组合已成为数据持久层的黄金搭档。模糊查询作为高频需求,其核心是通过SQL的LIKE操作符实现字符串模式匹配。Mybatis通过动态SQL和注解方式,将Java方法调用转换为高效的数据库查询语句,而SpringBoot则简化了整个框架的集成过程。
1.1 模糊查询的SQL基础
Mysql支持两种模糊匹配符号:
%
:匹配任意长度字符(包括零个字符)_
:匹配单个字符
示例:
SELECT * FROM users WHERE name LIKE '%张%'; -- 包含"张"的所有记录
SELECT * FROM products WHERE code LIKE 'A_B%'; -- 第二个字符为"B",首字符为"A"的记录
1.2 Mybatis的两种实现方式
- XML映射文件:通过
<select>
标签和${}
、#{}
参数占位符 - 注解方式:使用
@Select
注解直接编写SQL
二、完整实现步骤
2.1 环境准备
- 创建SpringBoot项目(2.7.x版本)
- 添加依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.2 实体类设计
@Data
public class User {
private Long id;
private String username;
private String email;
// 其他字段...
}
2.3 Mapper接口实现
方案一:XML映射文件
创建
UserMapper.xml
:<mapper namespace="com.example.mapper.UserMapper">
<select id="searchByKeyword" resultType="com.example.entity.User">
SELECT * FROM user
WHERE username LIKE CONCAT('%', #{keyword}, '%')
OR email LIKE CONCAT('%', #{keyword}, '%')
</select>
</mapper>
对应Mapper接口:
public interface UserMapper {
List<User> searchByKeyword(@Param("keyword") String keyword);
}
方案二:注解方式
@Mapper
public interface UserMapper {
@Select({
"<script>",
"SELECT * FROM user",
"WHERE username LIKE CONCAT('%', #{keyword}, '%')",
"<if test='emailSearch != null'>",
"OR email LIKE CONCAT('%', #{keyword}, '%')",
"</if>",
"</script>"
})
List<User> searchByKeyword(
@Param("keyword") String keyword,
@Param("emailSearch") Boolean emailSearch
);
}
2.4 Service层实现
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> searchUsers(String keyword) {
if (StringUtils.isEmpty(keyword)) {
return Collections.emptyList();
}
return userMapper.searchByKeyword(keyword);
}
// 带条件的高级搜索
public List<User> advancedSearch(String keyword, boolean searchEmail) {
return userMapper.searchByKeyword(keyword, searchEmail);
}
}
2.5 Controller层实现
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/search")
public ResponseEntity<List<User>> search(
@RequestParam String keyword,
@RequestParam(required = false, defaultValue = "false") boolean searchEmail) {
List<User> users = userService.advancedSearch(keyword, searchEmail);
return ResponseEntity.ok(users);
}
}
三、性能优化策略
3.1 索引优化
对搜索字段建立索引:
ALTER TABLE user ADD INDEX idx_username (username);
ALTER TABLE user ADD INDEX idx_email (email);
全文索引方案(Mysql 5.6+):
ALTER TABLE user ADD FULLTEXT INDEX ft_idx (username, email);
-- 使用MATCH AGAINST替代LIKE
SELECT * FROM user WHERE MATCH(username, email) AGAINST('张三' IN NATURAL LANGUAGE MODE);
3.2 分页处理
// Mapper接口
@Select("SELECT * FROM user WHERE username LIKE CONCAT('%', #{keyword}, '%') LIMIT #{offset}, #{size}")
List<User> searchWithPagination(
@Param("keyword") String keyword,
@Param("offset") int offset,
@Param("size") int size
);
// Service层
public PageResult<User> searchWithPage(String keyword, int page, int size) {
int offset = (page - 1) * size;
List<User> data = userMapper.searchWithPagination(keyword, offset, size);
long total = userMapper.countByKeyword(keyword); // 需额外实现计数方法
return new PageResult<>(data, total, page, size);
}
3.3 防SQL注入
- 永远使用
#{}
而非${}
(除非必要场景) - 对输入参数进行校验:
public List<User> safeSearch(String keyword) {
if (keyword == null || keyword.length() > 50) { // 限制长度
throw new IllegalArgumentException("Invalid keyword");
}
// 转义特殊字符(可选)
String safeKeyword = keyword.replaceAll("([%_])", "\\\\$1");
return userMapper.searchByKeyword(safeKeyword);
}
四、高级应用场景
4.1 多字段组合搜索
// Mapper接口
@Select({
"<script>",
"SELECT * FROM user",
"<where>",
"<if test='username != null'>",
"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>",
"</script>"
})
List<User> multiFieldSearch(
@Param("username") String username,
@Param("email") String email,
@Param("phone") String phone
);
4.2 拼音模糊搜索(需额外处理)
添加拼音字段:
ALTER TABLE user ADD COLUMN username_pinyin VARCHAR(100);
-- 通过触发器或应用层维护拼音字段
修改搜索SQL:
SELECT * FROM user
WHERE username LIKE CONCAT('%', #{keyword}, '%')
OR username_pinyin LIKE CONCAT('%', #{pinyinKeyword}, '%')
五、常见问题解决方案
5.1 中文乱码问题
确保数据库连接字符串包含字符集设置:
spring.datasource.url=jdbc
//localhost:3306/db?useUnicode=true&characterEncoding=utf8
检查表字段字符集:
SHOW CREATE TABLE user; -- 应显示CHARSET=utf8mb4
5.2 性能瓶颈排查
使用EXPLAIN分析查询:
EXPLAIN SELECT * FROM user WHERE username LIKE '%张%';
监控慢查询日志:
# application.properties
spring.datasource.hikari.data-source-properties.slowQueryThresholdMillis=2000
六、最佳实践总结
- 索引策略:对高频搜索字段建立单独索引,全文索引适用于长文本搜索
- 分页处理:必须实现分页,避免返回大量数据
- 安全防护:严格校验输入参数,防止SQL注入
- 性能监控:建立慢查询监控机制
- 扩展性设计:考虑使用Elasticsearch等专用搜索引擎处理复杂搜索需求
通过以上方案,开发者可以构建出高效、安全、可扩展的模糊查询功能。实际项目中,建议根据数据量和性能要求,在纯SQL模糊查询与专用搜索引擎之间做出合理选择。对于千万级数据量,建议采用Elasticsearch+Mysql的组合方案,既保证搜索灵活性,又维持事务一致性。
发表评论
登录后可评论,请前往 登录 或 注册