使用MyBatis-Plus构建复杂SQL查询条件

2026-07-12 11:27:07 82 次阅读

在使用 MyBatis-Plus 进行企业级 Java 开发时,复杂查询条件的构建往往是提升系统灵活性与可维护性的关键环节。相比传统 XML 手写 SQL,MyBatis-Plus 提供的 Wrapper 体系能够通过链式调用方式动态拼装查询逻辑,在多条件组合、嵌套逻辑、动态筛选等场景下显著降低开发成本。

在实际业务中,查询条件通常不是固定的,而是由前端参数动态决定,例如用户筛选、分页查询、权限过滤等。因此,掌握 MyBatis-Plus 构建复杂 SQL 查询条件的方法,是提升开发效率与代码质量的重要技能。


一、QueryWrapper 构建基础查询条件

QueryWrapper 是 MyBatis-Plus 中最常用的条件构造器,用于非 Lambda 方式的字段拼接。

常见基础用法如下:

Java
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1)
.like("username", "tom")
.ge("age", 18);

上述代码对应 SQL:

SQL
WHERE status = 1 AND username LIKE '%tom%' AND age >= 18

在简单查询中,QueryWrapper 已经能够满足大部分需求,但在复杂业务场景中,推荐进一步使用 LambdaQueryWrapper 来避免字段硬编码问题。


二、LambdaQueryWrapper 提升类型安全性

LambdaQueryWrapper 通过方法引用方式引用实体字段,避免字符串字段带来的拼写错误问题。

Java
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getStatus, 1)
.like(User::getUsername, "tom")
.ge(User::getAge, 18);

这种方式在重构时具有更高安全性,是企业项目中的推荐写法。


三、动态条件构建(核心能力)

在实际开发中,查询条件通常需要根据参数是否为空进行动态拼接。

Java
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

wrapper.eq(status != null, User::getStatus, status)
.like(StringUtils.isNotBlank(username), User::getUsername, username)
.ge(minAge != null, User::getAge, minAge)
.le(maxAge != null, User::getAge, maxAge);

关键点在于第一个 boolean 参数,当条件为 false 时,该查询条件不会拼接到 SQL 中,从而实现动态 SQL 效果。


四、复杂逻辑 OR / AND 嵌套查询

复杂查询中最常见的场景是 AND 与 OR 的嵌套组合,例如:

Java
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

wrapper.eq(User::getStatus, 1)
.and(w -> w.like(User::getUsername, "tom")
.or()
.like(User::getEmail, "tom"));

生成 SQL:

SQL
WHERE status = 1 AND (username LIKE '%tom%' OR email LIKE '%tom%')

MyBatis-Plus 通过 and()、or() 方法支持子条件封装,从而实现逻辑分组。


五、多层嵌套复杂查询示例

在复杂业务系统中,经常会遇到多层嵌套条件,例如:

Java
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

wrapper.eq(User::getStatus, 1)
.and(w1 -> w1
.ge(User::getAge, 18)
.and(w2 -> w2
.like(User::getUsername, "tom")
.or()
.like(User::getEmail, "tom")
)
);

对应 SQL:

SQL
WHERE status = 1
AND (
age >= 18
AND (
username LIKE '%tom%'
OR email LIKE '%tom%'
)
)

这种结构在权限系统、复杂筛选条件中非常常见。


六、IN / NOT IN / BETWEEN 等高级条件

MyBatis-Plus 对常见 SQL 语法提供了完整封装。

IN 查询

Java
wrapper.in(User::getId, idList);

NOT IN 查询

Java
wrapper.notIn(User::getId, idList);

BETWEEN 查询

Java
wrapper.between(User::getCreateTime, startTime, endTime);

这些方法在批量过滤、时间范围查询中非常高效。


七、排序与分页组合查询

复杂查询通常离不开分页与排序。

Java
wrapper.orderByDesc(User::getCreateTime);

分页配合 MyBatis-Plus 分页插件:

Java
Page<User> page = new Page<>(current, size);
userMapper.selectPage(page, wrapper);

在高并发系统中,分页与条件构建的组合是性能优化的重要基础。


八、子查询与 EXISTS 场景处理

MyBatis-Plus 支持通过 apply 方法实现更复杂 SQL:

Java
wrapper.apply("exists (select 1 from order o where o.user_id = user.id and o.status = 1)");

该方式适用于无法通过 Wrapper 表达的复杂业务逻辑,例如 EXISTS、复杂 JOIN 条件等。


九、常见优化实践

在构建复杂查询条件时,应注意以下优化原则:

  1. 避免过度嵌套,保持逻辑清晰

  2. 优先使用 LambdaQueryWrapper 提高可维护性

  3. 动态条件必须避免 null 值污染 SQL

  4. 大数据查询慎用 like 模糊匹配

  5. 复杂 SQL 优先拆分为方法或 Service 层封装

  6. 尽量减少 apply 原生 SQL 使用频率


十、复杂查询封装设计思路

在企业级项目中,建议将复杂查询条件封装为独立方法:

Java
private LambdaQueryWrapper<User> buildCondition(UserQueryDTO dto) {
return Wrappers.lambdaQuery(User.class)
.eq(dto.getStatus() != null, User::getStatus, dto.getStatus())
.like(StringUtils.isNotBlank(dto.getKeyword()), User::getUsername, dto.getKeyword());
}

这种方式可以显著提升代码复用性,并降低 Controller 层复杂度。


MyBatis-Plus 在复杂 SQL 查询构建方面提供了强大的链式 API 支持,使开发者能够在无需编写大量 XML 的情况下完成灵活多变的业务查询逻辑。合理使用 Wrapper、动态条件与嵌套逻辑,可以在保证代码可读性的同时提升系统扩展能力。

[MyBatis-Plus, Java持久层框架, SQL查询优化, 动态查询条件, LambdaQueryWrapper]