深入理解 MyBatis-Plus 的 QueryWrapper:动态 SQL 构建的利器
关键词:MyBatis-Plus、QueryWrapper、动态 SQL、Java、ORM
一、引言
在 Java 后端开发中,MyBatis-Plus(简称 MP)作为 MyBatis 的增强工具,极大地简化了 CRUD 操作。而其中最核心的功能之一,就是动态 SQL 的条件构造器 —— QueryWrapper
。
你是否还在手写 XML 中的 <if test="...">
?是否还在为拼接 SQL 条件而烦恼?QueryWrapper
将带你告别这些痛苦。
二、什么是 QueryWrapper?
QueryWrapper
是 MyBatis-Plus 提供的条件构造器,用于构建 WHERE
子句的查询条件。它通过链式调用的方式,实现了类型安全、可读性强、可复用的 SQL 构造。
类图关系(简化)
QueryWrapper ← AbstractWrapper ← Wrapper
Wrapper
:抽象根类,定义了条件构造的基本能力。AbstractWrapper
:封装了条件拼接逻辑。QueryWrapper
:专用于查询操作,支持SELECT ... WHERE ...
。
三、快速入门
1. 引入依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.5</version>
</dependency>
2. 实体类
@Data
@TableName("user")
public class User {private Long id;private String name;private Integer age;private String email;
}
3. Mapper 接口
public interface UserMapper extends BaseMapper<User> {}
4. 使用 QueryWrapper 查询
@Autowired
private UserMapper userMapper;public List<User> getUsers(String name, Integer minAge) {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.like(StringUtils.isNotBlank(name), "name", name).ge(minAge != null, "age", minAge);return userMapper.selectList(wrapper);
}
四、核心方法详解
方法名 | 说明 | 示例 |
---|---|---|
eq | 等于 | eq("age", 20) → age = 20 |
ne | 不等于 | ne("age", 20) → age <> 20 |
gt / ge | 大于 / 大于等于 | gt("age", 18) → age > 18 |
lt / le | 小于 / 小于等于 | lt("age", 30) → age < 30 |
like | 模糊查询 | like("name", "张") → name LIKE '%张%' |
in | 包含 | in("id", 1, 2, 3) → id IN (1,2,3) |
isNull / isNotNull | 空值判断 | isNull("email") → email IS NULL |
orderByAsc / orderByDesc | 排序 | orderByDesc("create_time") |
五、进阶用法
1. 条件优先级(括号控制)
wrapper.and(w -> w.eq("age", 20).or().eq("name", "Tom")).eq("status", 1);
生成的 SQL:
WHERE (age = 20 OR name = 'Tom') AND status = 1
2. 只查询部分字段
wrapper.select("id", "name").eq("age", 25);
3. 排除字段
wrapper.select(User.class, info -> !info.getColumn().equals("password")).eq("status", 1);
六、实战案例:分页 + 多条件搜索
public IPage<User> searchUsers(String name, Integer minAge, Integer maxAge, int current, int size) {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.like(StringUtils.isNotBlank(name), "name", name).ge(minAge != null, "age", minAge).le(maxAge != null, "age", maxAge).orderByDesc("create_time");Page<User> page = new Page<>(current, size);return userMapper.selectPage(page, wrapper);
}
七、常见误区与注意事项
误区 | 正确做法 |
---|---|
直接拼接字段名 | 使用 LambdaQueryWrapper 避免硬编码 |
忽略空值判断 | 使用带 condition 参数的重载方法 |
滥用 or() | 使用 and(Consumer<Wrapper>) 明确优先级 |
忽略 SQL 注入 | 不要手动拼接字符串,使用 MP 提供的 API |
八、LambdaQueryWrapper:类型安全升级版
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(name), User::getName, name).ge(minAge != null, User::getAge, minAge);
优点:
- 编译期检查字段名
- 避免魔法字符串
- 支持方法引用
九、总结
特性 | 描述 |
---|---|
简洁 | 链式调用,告别 XML |
灵活 | 动态条件,支持复杂逻辑 |
安全 | 防止 SQL 注入 |
可维护 | 与实体类联动,易于重构 |
建议:
- 简单查询用
QueryWrapper
- 生产环境优先使用
LambdaQueryWrapper
- 复杂 SQL 仍可用 XML 或
@Select
十、参考资料
- MyBatis-Plus 官方文档
- GitHub:baomidou/mybatis-plus
- 《MyBatis-Plus 实战》