MyBatis-Plus的Wrapper核心体系

MyBatis-Plus的Wrapper核心体系

MyBatis-Plus的Wrapper核心体系

MyBatis-Plus 中的 Wrapper 体系是其条件构造器的核心组成部分,以 Wrapper 为顶层接口、AbstractWrapper 为核心抽象类,是一套基于面向对象思想设计的、用于动态构建 SQL 条件子句的类型化 API 体系。

Wrapper 体系作为 MP 的核心组件,深度集成到 BaseMapper、IService 等核心 CRUD 接口的关键方法中,是实现动态条件查询、条件更新的核心载体。

其核心能力与特性可归纳为:

  • 动态条件组装:支持根据业务逻辑动态添加 SQL 条件,适配多场景的动态查询 / 更新需求,无需编写固定条件的 SQL 片段;
  • 安全防护能力:内部基于 JDBC 参数占位符(?)机制自动完成参数绑定和特殊字符转义,从底层规避手动拼接 SQL 字符串导致的 SQL 注入风险;
  • 语法友好性:提供链式调用语法简化条件拼接逻辑,同时支持 Lambda 表达式指定实体类字段,通过实体类方法引用代替字符串,解决字符串字段名硬编码的风险;
  • 逻辑扩展性:原生支持多层 AND/OR 嵌套逻辑、自定义 SQL 片段嵌入,也可通过继承AbstractWrapper等抽象类扩展自定义条件构造逻辑,满足复杂业务场景的个性化需求;
  • 场景适配性:通过 QueryWrapper/LambdaQueryWrapper(查询场景)、UpdateWrapper/LambdaUpdateWrapper(更新场景)等细分实现类精准适配不同数据操作场景 ------ 其中 Lambda 版本编译期校验字段合法性,非 Lambda 版本更灵活但存在硬编码风险,整体遵循单一职责设计原则。

Wrapper 核心体系结构如图:

图中所示并不完全详细,跳过了中间抽象层,实际上 AbstractWrapper 核心通用抽象类的直接子类包含 AbstractQueryWrapper(查询场景抽象)、AbstractUpdateWrapper(更新场景抽象)和 AbstractLambdaWrapper(Lambda 通用抽象)

  • AbstractQueryWrapper 的唯一实现类是 QueryWrapper,AbstractUpdateWrapper 的唯一实现类是 UpdateWrapper;
  • AbstractLambdaWrapper 进一步派生出 AbstractLambdaQueryWrapper(Lambda 查询抽象)、AbstractLambdaUpdateWrapper(Lambda 更新抽象),二者的实现类分别为 LambdaQueryWrapper、LambdaUpdateWrapper。

QueryWrapper

QueryWrapper 是 MyBatis-Plus 核心的查询条件构造器,核心用于替代手写 SQL 查询语句中的 WHERE 子句。它以面向对象的链式调用方式灵活构造各类查询条件,主要适配单表查询场景,也可支持简易多表关联查询的条件拼接,能大幅简化 SQL 条件编写流程,提升代码可读性与开发效率。

下面进行核心使用场景及示例

情况1:单表条件查询

java 复制代码
@SpringBootTest
public class MybatisWrapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void test(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.between("age", 20, 30)
                .isNotNull("email");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }
}

组装的 sql 语句为:

sql 复制代码
SELECT id,name,age,email FROM user WHERE (age BETWEEN ? AND ? AND email IS NOT NULL)
  • 比较条件:
    eq:=,ne:<>,gt: >,ge:>=,lt:<,le:<=
  • 范围查询:
    in:IN (?,?,...),notIn:NOT IN (?,?,...)
    between:BETWEEN ? AND ?
    notBetween:NOT BETWEEN ? AND ?
  • 空值判断:
    isNull:IS NULL
    isNotNull:IS NOT NULL

情况2:组装模糊查询

java 复制代码
    @Test
    public void test01(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name", "a");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

组装的 sql 语句为:

sql 复制代码
SELECT id,name,age,email FROM user WHERE (name LIKE ?)

模糊查询:

like:LIKE '% 值 %'

likeLeft:LIKE '% 值'

likeRight:LIKE ' 值 %'

notLike:NOT LIKE '% 值 %'

情况3:组装排序条件

java 复制代码
    @Test
    public void test02(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .orderByDesc("age")
                .orderByAsc("id");
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }

组装的 sql 语句为:

sql 复制代码
SELECT id,name,age,email FROM user ORDER BY age DESC,id ASC
  • 排序:
    orderByAsc:ORDER BY 字段 ASC,可按照多字段进行排序
    orderByDesc:ORDER BY 字段 DESC,可按照多字段进行排序
  • 分组:
    groupBy:GROUP BY 字段
    having:HAVING sql,用于分组后筛选

情况4:删除条件

条件构造器也可以构建删除语句的条件

java 复制代码
    @Test
    public void test03(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println("受影响的行数:" + result);
    }

组装的 sql 语句为:

sql 复制代码
DELETE FROM user WHERE (email IS NULL)

情况5:条件优先级

使用逻辑运算

java 复制代码
    @Test
    public void test04() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .like("name", "a")
                .gt("age", 20)
                .or()
                .isNull("email");
        User user = new User();
        user.setAge(18);
        user.setEmail("user@123.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("受影响的行数:" + result);
    }

组装的 sql 语句为:

sql 复制代码
UPDATE user SET age=?, email=? WHERE (name LIKE ? AND age > ? OR email IS NULL)

该方法意为:更新表中(姓名包含 "a" 且年龄 > 20)或者邮箱为 NULL 的所有用户,将其年龄改为 18邮箱改为 user@123.com

  • and:拼接 AND 条件(默认)
  • or:拼接 OR 条件
  • nested:嵌套条件(优先执行)

若想提升 OR 优先级可以使用 and() 或 nested() 方法嵌套条件

使用 and() 方法嵌套条件

java 复制代码
    @Test
    public void test05() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .like("username", "a")
                .and(i -> i.gt("age", 20).or().isNull("email"));
        User user = new User();
        user.setAge(18);
        user.setEmail("user@123.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("受影响的行数:" + result);
    }

使用 nested() 嵌套条件

java 复制代码
    @Test
    public void test05_1() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .like("name", "a")
                .nested(i -> i.gt("age", 20).or().isNull("email"));
        User user = new User();
        user.setAge(18);
        user.setEmail("user@123.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("受影响的行数:" + result);
    }

组装的 sql 语句均为:

sql 复制代码
UPDATE user SET age=?, email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))

情况6:字段筛选

只查指定字段

java 复制代码
    @Test
    public void test06() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("name", "age");
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        maps.forEach(System.out::println);
    }

组装的 sql 为:

sql 复制代码
SELECT name,age FROM user

若我们选择返回值类型为 List<User>,那么实体类中引用类型字段对应的列未被 select() 指定查询时,该字段的值为 null,基本数据类型字段对应的列未被 select() 指定查询时,该字段会取基本类型的默认值,如图:

字段筛选实现聚合查询

java 复制代码
    @Test
    public void test06_1(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("email", "test");
        queryWrapper.select("COUNT(*) as total_count");
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        maps.forEach(System.out::println);
    }

组装的 sql 为:

sql 复制代码
SELECT COUNT(*) as total_count FROM user WHERE (email LIKE ?)

总结:在 MyBatis-Plus 中,selectMaps () 与 select () 是高频且实用的搭配

select () 用于精准指定需要查询的字段,而 selectMaps () 则适配两类核心场景 ------ 一是仅需查询部分字段,无需封装为实体类以简化开发,二是查询结果包含聚合函数、自定义字段别名等无法直接映射到实体类的情况,能以 Map<String, Object> 形式灵活接收结果。

情况7:实现子查询

java 复制代码
    @Test
    public void test07() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("id", "select id from user where id <= 3");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

inSql() 是为查询条件拼接 IN 关键字,且 IN 后的括号内直接填入自定义的子查询 SQL 片段,最终生成 字段 IN (子查询语句) 的 SQL 条件

组装的 sql 语句为:

sql 复制代码
SELECT id,name,age,email FROM user WHERE (id IN (select id from user where id <= 3))

情况8:分页查询

结合 MP 分页插件

java 复制代码
    @Test
    public void test08(){
        Page<User> page = new Page<>(1, 5);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("email", "test");
        userMapper.selectPage(page, queryWrapper);
        List<User> list = page.getRecords();
        list.forEach(System.out::println);
    }

组装的 sql 为:

sql 复制代码
SELECT id,name,age,email FROM user WHERE (email LIKE ?) LIMIT ?

UpdateWrapper

UpdateWrapper 是 MyBatis-Plus 专为带条件的更新操作设计的核心工具,用于拼接更新字段、动态 / 复杂筛选条件,替代原生 SQL 拼接的繁琐与易出错问题。

简化更新操作的 WHERE 条件构建 + SET 字段赋值,无需手动拼接 SQL,同时通过参数化查询防止 SQL 注入;

核心特性:链式编程、动态条件、支持字段算术运算、自定义 SQL 片段、自动映射实体 / 数据库字段。

情况1: T entity 为 null

java 复制代码
    @Test
    public void test09() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .set("age", 18)
                .set("email", "user@123.com")
                .like("name", "a")
                .and(i -> i.gt("age", 20).or().isNull("email"));
        int result = userMapper.update(null, updateWrapper);
        System.out.println(result);
    }

BaseMapper 提供的 update 方法中,第一个参数 T entity:

非 null 时,用于提供更新字段(后面有例子进行演示);

null 值意为放弃通过实体设置更新字段,此时更新字段完全依赖第二个参数 UpdateWrapper 的 set/setSql 方法指定,而 UpdateWrapper 中的 like/and/gt 等方法仅用于构建 WHERE 筛选条件。

组装的 sql 语句为:

sql 复制代码
UPDATE user SET age=?,email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))

需要注意的是,若不使用 lambda 嵌套,直接写 and().gt().or().isNull(),会导致OR会和外层条件同级,条件的优先级产生错误。

情况2: T entity 不为 null

java 复制代码
    @Test
    public void test10(){
        User user = new User();
        user.setAge(18);
        user.setEmail(null);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .like("name", "a")
                .set("email", "user@123.com");
        userMapper.update(user, updateWrapper);
    }

BaseMapper 提供的 update 方法中第一个参数 T entity 若传入非 null 实体对象,MP 会基于实体的非 null 字段生成 SET 语句,实体中为 null 的字段不会参与更新,避免覆盖原有值。

组装的 sql 语句为:

sql 复制代码
UPDATE user SET age=?, email=? WHERE (name LIKE ?)

若实体(entity)和 UpdateWrapper 同时设置了同一个字段,那么 UpdateWrapper 的 set / setSql 会覆盖实体的字段值 ------ 原因是 MP 拼接 SET 子句时,Wrapper 的 set 逻辑执行在后,最终生成的 SET 语句中,Wrapper 设定的字段值会覆盖实体的同名字段值。

LambdaQueryWrapper

LambdaQueryWrapper 是 MyBatis-Plus 提供的 Lambda 风格类型的查询条件构造器,继承自 AbstractLambdaWrapper,核心用于构建 SQL 的 SELECT 语句的查询条件。

该组件通过 Lambda 方法引用(实体类::字段)替代字符串硬编码指定字段名,将字段合法性校验前置至编译阶段,解决了传统 QueryWrapper 字段名硬编码导致的拼写错误、重构成本高、运行时风险等问题;

同时支持链式调用、动态条件构造、复杂嵌套条件拼接,可高效、规范地构建各类查询条件,保障查询逻辑的类型安全与可维护性。

java 复制代码
    @Test
    public void test14() {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .like(User::getName, "a") .ge(User::getAge, 10)
                .le(User::getAge, 24);
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }

组装的 sql 语句为:

sql 复制代码
SELECT id,name,age,email FROM user WHERE (name LIKE ? AND age >= ? AND age <= ?)

LambdaUpdateWrapper

LambdaUpdateWrapper 是 MyBatis-Plus 提供的 Lambda 风格类型的更新条件构造器,继承自 AbstractLambdaWrapper,核心用于构建 SQL 的 UPDATE 语句的更新字段与更新过滤条件。

该组件通过 Lambda 方法引用(实体类::字段)替代字符串硬编码指定更新字段和条件字段,将字段合法性校验前置至编译阶段,解决了传统 UpdateWrapper 字段名硬编码导致的拼写错误、重构成本高、运行时风险等问题;

同时支持链式调用、动态条件构造、复杂嵌套条件拼接,除继承 AbstractLambdaWrapper 体系下所有 WHERE 条件构造能力外,还扩展了 set/setSql 等专属方法用于精准配置更新字段,可高效、规范地构建各类更新逻辑,保障更新操作的类型安全与可维护性。

java 复制代码
    @Test
    public void test15() {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(User::getAge, 18)
                .set(User::getEmail, "user@123.com")
                .like(User::getName, "a")
                .and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));
        User user = new User();
        int result = userMapper.update(user, updateWrapper);
        System.out.println("受影响的行数:" + result);
    }

组装的 sql 语句为:

sql 复制代码
UPDATE user SET age=?,email=? WHERE (name LIKE ? AND (age < ? OR email IS NULL))
相关推荐
曼巴UE56 小时前
UE C++ 字符串的操作
java·开发语言·c++
凛_Lin~~6 小时前
安卓/Java语言基础八股文
java·开发语言·安卓
透明的玻璃杯6 小时前
sqlite数据库链接池二
数据库·oracle·sqlite
老华带你飞6 小时前
出行旅游安排|基于springboot出行旅游安排系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·spring·旅游
舒一笑6 小时前
在低配云服务器上实现自动化部署:Drone CI + Gitee Webhook 的轻量级实践
前端·后端·程序员
李广坤6 小时前
Rust基本使用
后端·rust
nvvas6 小时前
Java AI开发入门指南
java·人工智能
元亓亓亓6 小时前
考研408--操作系统--day8--操作系统--虚拟内存&请求分页&页面置换/分配
android·java·开发语言·虚拟内存
我是你们的明哥6 小时前
Java优先级队列(PriorityQueue)详解:原理、用法与实战示例
后端·算法