MyBatisPlus之Wrapper条件构造器—构建复杂查询
在MyBatisPlus(简称MP)的Wrapper条件构造器无疑是提升查询效率的利器,它摆脱了传统XML中繁琐的SQL拼接,通过面向对象的方式快速构建复杂查询条件,让我们在处理多条件查询时更加得心应手。
一、Wrapper基础知识
Wrapper是MP提供的一套条件构造抽象类,用于动态生成SQL的WHERE条件。它的核心价值在于:
- 替代XML中的动态SQL:无需在XML中写
<if>
<where>
等标签,通过Java代码直接拼接条件。 - 支持链式编程:语法简洁直观,可读性强,如
eq("name", "张三").gt("age", 18)
。 - 适配复杂场景:轻松处理多条件组合、嵌套查询、排序、分页等需求。
MP中常用的Wrapper实现类有:
QueryWrapper
:最常用,支持所有查询条件构造。UpdateWrapper
:用于更新操作的条件构造(如set("name", "李四").eq("id", 1)
)。LambdaQueryWrapper
:通过Lambda表达式构建条件,避免硬编码字段名(推荐,减少字段名写错的风险)。
二、核心API与基础用法
Wrapper的API命名遵循“见名知意”原则,以下是开发中最常用的方法分类及示例(以QueryWrapper
为例,基于User表:id、name、age、email字段)。
1. 比较条件
方法 | 说明 | 示例 | 对应SQL |
---|---|---|---|
eq(R column, Object val) | 等于(=) | eq("name", "张三") | where name = '张三' |
ne(R column, Object val) | 不等于(≠) | ne("age", 20) | where age <> 20 |
gt(R column, Object val) | 大于(>) | gt("age", 18) | where age > 18 |
ge(R column, Object val) | 大于等于(≥) | ge("age", 18) | where age >= 18 |
lt(R column, Object val) | 小于(<) | lt("age", 30) | where age < 30 |
le(R column, Object val) | 小于等于(≤) | le("age", 30) | where age <= 30 |
示例:查询年龄大于18且小于30的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 18)
.lt("age", 30);
List<User> userList = userMapper.selectList(queryWrapper);
2. 模糊查询
方法 | 说明 | 示例 | 对应SQL |
---|---|---|---|
like(R column, Object val) | 包含(%val%) | like("name", "张") | where name like '%张%' |
likeLeft(R column, Object val) | 左模糊(%val) | likeLeft("name", "三") | where name like '%三' |
likeRight(R column, Object val) | 右模糊(val%) | likeRight("name", "张") | where name like '张%' |
notLike(R column, Object val) | 不包含 | notLike("email", "qq.com") | where email not like '%qq.com%' |
示例:查询姓名以“张”开头且邮箱不含“qq.com”的用户
queryWrapper.likeRight("name", "张")
.notLike("email", "qq.com");
3. 逻辑组合
方法 | 说明 | 示例 | 对应SQL |
---|---|---|---|
and(Consumer<Param> consumer) | 拼接AND条件(嵌套) | and(qw -> qw.gt("age",18).lt("age",30)) | where (age > 18 and age < 30) |
or(Consumer<Param> consumer) | 拼接OR条件(嵌套) | or(qw -> qw.eq("name","张三").or().eq("name","李四")) | where (name = '张三' or name = '李四') |
not() | 对后续条件取反 | not().eq("name", "张三") | where not (name = '张三') |
示例:查询(年龄>18且邮箱含“@163.com”)或(姓名为“李四”且年龄=25)的用户
queryWrapper.and(qw -> qw.gt("age", 18).like("email", "@163.com"))
.or(qw -> qw.eq("name", "李四").eq("age", 25));
4. 其他常用条件
in(R column, Collection<?> coll)
:包含在集合中,如in("id", Arrays.asList(1,2,3))
→where id in (1,2,3)
。isNull(R column)
:字段为NULL,如isNull("email")
→where email is null
。orderByAsc(R... columns)
:升序排序,如orderByAsc("age", "id")
→order by age asc, id asc
。last(String sql)
:直接拼接SQL在末尾(慎用,可能引发SQL注入),如last("limit 1")
→ 强制只查1条。
三、LambdaQueryWrapper:避免硬编码的最佳实践
LambdaQueryWrapper
通过Lambda表达式引用实体类的字段(如User::getName
),彻底避免了字符串字段名写错的问题,是推荐的使用方式。
示例:用LambdaQueryWrapper查询年龄≥20且姓名包含“李”的用户
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery.ge(User::getAge, 20) // 引用User类的age字段
.like(User::getName, "李"); // 引用name字段
List<User> userList = userMapper.selectList(lambdaQuery);
优势:当实体类字段名修改时,IDE会直接报错,避免线上因字段名拼写错误导致的BUG。
四、构建复杂查询:多表关联与子查询
Wrapper不仅支持单表查询,还能通过apply
或exists
等方法处理多表关联和子查询。
1. 多表关联查询(以关联Role表为例)
需求:查询“张三”拥有的所有角色(用户表user与角色表role通过中间表user_role关联)。
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("u.name", "张三") // u为user表别名
.apply("u.id = ur.user_id") // 关联中间表user_role(ur)
.apply("ur.role_id = r.id") // 关联角色表role(r)
.select("r.id, r.role_name"); // 只查询角色表的字段
List<Map<String, Object>> roleList = userMapper.selectMaps(queryWrapper);
2. 子查询(exists)
需求:查询存在“年龄>30”的用户的部门(假设用户表有dept_id字段)。
LambdaQueryWrapper<Dept> deptQuery = new LambdaQueryWrapper<>();
deptQuery.exists("select 1 from user u where u.dept_id = dept.id and u.age > 30");
List<Dept> deptList = deptMapper.selectList(deptQuery);
注意事项
- 字段名与数据库一致性:Wrapper的字段名需与数据库表字段一致(而非实体类的
@TableField
别名,除非用Lambda方式)。 - SQL注入风险:
last()
和apply()
方法会直接拼接SQL,避免传入用户输入的参数,必要时用{0}
占位符(如apply("date_format(create_time, '%Y-%m') = {0}", "2023-10")
)。 - 条件优先级:复杂条件建议用
and()
/or()
的嵌套Consumer,明确优先级(类似SQL中的括号)。 - 分页查询:结合MP的
IPage
接口,Wrapper可直接作为分页条件,如userMapper.selectPage(page, queryWrapper)
。
总结
Wrapper条件构造器是MyBatisPlus简化查询的核心工具,通过链式API和Lambda表达式,让复杂查询条件的构建变得简洁高效,建议在实际开发中优先使用LambdaQueryWrapper
,并合理利用and()
/or()
的嵌套处理复杂逻辑,同时注意规避SQL注入风险。
若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ