当前位置: 首页 > news >正文

深入浅出 MyBatis-Plus Wrapper:让条件构造更简单高效

在 MyBatis-Plus 中,Wrapper 是构建查询条件、更新条件的核心工具,它能帮助我们摆脱繁琐的 SQL 字符串拼接,通过链式 API 优雅地组装各种复杂条件。本文将系统讲解 Wrapper 的体系结构、核心用法及实战技巧,从基础的 QueryWrapper 到类型安全的 LambdaWrapper,带你全方位掌握 MyBatis-Plus 的条件构造能力。 

一、Wrapper 体系:从抽象到具体的条件构造器

Wrapper 是 MyBatis-Plus 中用于构建 SQL 条件的抽象层,其核心设计采用了 "抽象类 + 接口" 的组合模式,形成了一套完整的条件构造体系。理解这套体系的继承关系,能帮助我们更快掌握各类 Wrapper 的适用场景。

1.1 Wrapper 核心继承关系

Wrapper 的顶层结构如下(可通过 IDE 的Ctrl+H查看类继承树):

Wrapper(最顶层抽象类)
└── AbstractWrapper(查询条件封装,生成WHERE子句)├── QueryWrapper(查询条件构造器,用于SELECT/DELETE)├── UpdateWrapper(更新条件构造器,用于UPDATE)└── AbstractLambdaWrapper(Lambda语法支持)├── LambdaQueryWrapper(Lambda风格的查询构造器)└── LambdaUpdateWrapper(Lambda风格的更新构造器)

 

1.2 AbstractWrapper 的核心接口

AbstractWrapper 实现了 4 个核心接口,这些接口定义了条件构造的基础能力:

接口作用
Compare提供比较条件方法(eq/ne/gt/lt/between 等),处理属性与值的比较
Nested支持嵌套条件(通过 and/or 组合子条件),实现复杂逻辑的括号包裹
Join处理表连接(INNER JOIN/LEFT JOIN 等),支持多表查询时的关联条件
Func函数式接口,用于封装可复用的条件逻辑,简化代码复用

这些接口的方法均为默认方法(Java 8+),子类可直接使用或重写,这也是 Wrapper 能实现链式调用的核心原因。

二、QueryWrapper:查询与删除的条件构造利器

QueryWrapper 是最常用的条件构造器,主要用于 SELECT 查询和 DELETE 删除操作,支持各种条件组合、排序、子查询等场景。

2.1 基础查询:组合多条件

场景:查询用户名包含 "a"、年龄在 20-30 之间、邮箱不为 null 的用户。

@Test
public void testQueryWrapperBasic() {QueryWrapper<People> queryWrapper = new QueryWrapper<>();// 链式调用组装条件queryWrapper.like("username", "a") // 用户名 LIKE '%a%'.between("age", 20, 30) // 年龄 BETWEEN 20 AND 30.isNotNull("email"); // 邮箱 IS NOT NULLList<People> peopleList = peopleMapper.selectList(queryWrapper);peopleList.forEach(System.out::println);
}

 

生成的 SQL

SELECT id, username AS name, age, email, is_deleted 
FROM t_people 
WHERE is_deleted=0 
AND (username LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)

关键点

  • 逻辑删除字段(如is_deleted)会自动加入条件(需配置逻辑删除);
  • 条件默认通过AND连接,可通过or()方法切换为OR

2.2 排序:orderBy 系列方法

场景:按年龄降序、ID 升序查询所有用户。

@Test
public void testQueryWrapperOrder() {QueryWrapper<People> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("age") // 按年龄降序.orderByAsc("id"); // 按ID升序List<People> peopleList = peopleMapper.selectList(queryWrapper);peopleList.forEach(System.out::println);
}

生成的 SQL

SELECT id, username AS name, age, email, is_deleted 
FROM t_people 
WHERE is_deleted=0 
ORDER BY age DESC, id ASC

2.3 构建删除条件

场景:删除邮箱为 null 的用户(逻辑删除)。

@Test
public void testQueryWrapperDelete() {QueryWrapper<People> queryWrapper = new QueryWrapper<>();queryWrapper.isNull("email"); // 邮箱为nullint rows = peopleMapper.delete(queryWrapper);System.out.println("受影响的行数:" + rows);
}

生成的 SQL

UPDATE t_people SET is_deleted=1 
WHERE is_deleted=0 AND (email IS NULL)

 

说明:若配置了逻辑删除,delete方法实际执行 UPDATE;若未配置,则执行物理删除(DELETE 语句)。

2.4 条件优先级:括号与逻辑组合

场景:更新满足以下条件的用户:(用户名包含 "a" 且年龄 > 20)(邮箱为 null)。

@Test
public void testQueryWrapperPriority() {QueryWrapper<People> queryWrapper = new QueryWrapper<>();queryWrapper.like("username", "a").gt("age", 20).or() // 切换为OR连接.isNull("email");People update = new People();update.setAge(18);update.setEmail("people@qcby.com");int rows = peopleMapper.update(update, queryWrapper);System.out.println("受影响的行数:" + rows);
}

生成的 SQL

UPDATE t_people SET age=?, email=? 
WHERE is_deleted=0 
AND (username LIKE ? AND age > ? OR email IS NULL)

 

进阶:若需调整优先级(如 "用户名包含 a 且(年龄 > 20 或邮箱为 null)"),可使用and(i -> ...)嵌套条件:

queryWrapper.like("username", "a").and(i -> i.gt("age", 20).or().isNull("email")); // 嵌套条件用括号包裹

生成的 SQL 条件

AND (username LIKE ? AND (age > ? OR email IS NULL))

2.5 自定义查询字段:select 子句

场景:只查询用户名和年龄字段,减少数据传输。

@Test
public void testQueryWrapperSelect() {QueryWrapper<People> queryWrapper = new QueryWrapper<>();queryWrapper.select("username", "age"); // 指定查询字段// 使用selectMaps()返回Map列表(避免实体类未查询字段为null)List<Map<String, Object>> maps = peopleMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);
}

生成的 SQL

SELECT username, age 
FROM t_people 
WHERE is_deleted=0

 

2.6 子查询:inSql 方法

场景:查询 ID 在子查询结果中的用户(子查询:ID>=3 的用户)。

    @Testpublic void testQueryWrapperSubQuery() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();// 字段"id"的值在子查询结果中queryWrapper.inSql("uid", "select uid from t_user where uid >= 3");List<User> peopleList = userMapper.selectList(queryWrapper);peopleList.forEach(System.out::println);}

 

生成的 SQL

SELECT id, username AS name, age, email, is_deleted 
FROM t_people 
WHERE is_deleted=0 
AND (id IN (select id from t_people where id <= 3))

 

三、UpdateWrapper:专注更新操作的条件构造器

UpdateWrapper 与 QueryWrapper 的区别在于:它更专注于更新场景,可直接通过set方法设置字段值,无需额外创建实体类。

3.1 基本用法:组合更新条件与字段

场景:将(年龄 > 20 或邮箱为 null)且用户名包含 "a" 的用户,年龄改为 18,邮箱改为 "user@qcby.com"。

@Test
public void testUpdateWrapper() {UpdateWrapper<People> updateWrapper = new UpdateWrapper<>();updateWrapper.set("age", 18) // 直接设置字段值.set("email", "user@qcby.com").like("username", "a").and(i -> i.gt("age", 20).or().isNull("email")); // 嵌套条件// 第一个参数为null,因为更新字段已通过set()设置int rows = peopleMapper.update(null, updateWrapper);System.out.println("受影响的行数:" + rows);
}

生成的 SQL

UPDATE t_people SET age=?, email=? 
WHERE is_deleted=0 
AND (username LIKE ? AND (age > ? OR email IS NULL))

 

优势:无需创建实体类,直接在 Wrapper 中设置更新字段,适合部分字段更新场景。

四、Condition 参数:简化条件判断逻辑

在实际开发中,条件往往来源于用户输入(可能为 null),需要先判断条件是否有效再组装。MyBatis-Plus 提供了带condition参数的重载方法,简化这种判断。

4.1 传统方式:大量 if 判断

@Test
public void testConditionTraditional() {String username = null; // 用户未输入用户名Integer ageBegin = 10; // 开始年龄Integer ageEnd = 24; // 结束年龄QueryWrapper<People> queryWrapper = new QueryWrapper<>();// 手动判断条件是否有效if (StringUtils.isNotBlank(username)) {queryWrapper.like("username", username);}if (ageBegin != null) {queryWrapper.ge("age", ageBegin);}if (ageEnd != null) {queryWrapper.le("age", ageEnd);}List<People> peopleList = peopleMapper.selectList(queryWrapper);
}

 

4.2 优化方式:带 Condition 的链式调用

@Test
public void testConditionOptimized() {String username = null;Integer ageBegin = 10;Integer ageEnd = 24;QueryWrapper<People> queryWrapper = new QueryWrapper<>();// condition为true时才组装该条件queryWrapper.like(StringUtils.isNotBlank(username), "username", username).ge(ageBegin != null, "age", ageBegin).le(ageEnd != null, "age", ageEnd);List<People> peopleList = peopleMapper.selectList(queryWrapper);
}

 

效果:当conditionfalse时,该条件不会被组装到 SQL 中,避免了大量 if 语句,代码更简洁。

五、LambdaWrapper:类型安全的条件构造

传统 Wrapper 通过字符串指定字段名(如"username"),存在硬编码问题(字段名修改后编译不报错,运行时才发现)。LambdaWrapper 通过方法引用(如People::getName)解决这一问题,实现编译时字段校验。

5.1 LambdaQueryWrapper:查询场景

场景:使用 Lambda 风格查询用户名包含 "a"、年龄在 10-24 之间的用户。

@Test
public void testLambdaQueryWrapper() {String username = "a";Integer ageBegin = 10;Integer ageEnd = 24;LambdaQueryWrapper<People> lambdaWrapper = new LambdaQueryWrapper<>();lambdaWrapper// 方法引用:People::getName 对应字段username(需与实体类属性一致).like(StringUtils.isNotBlank(username), People::getName, username).ge(ageBegin != null, People::getAge, ageBegin).le(ageEnd != null, People::getAge, ageEnd);List<People> peopleList = peopleMapper.selectList(lambdaWrapper);
}

 

优势

  • 字段名通过方法引用指定,编译时检查,避免拼写错误;
  • 无需记忆数据库字段名,直接使用实体类属性,降低心智负担。

5.2 LambdaUpdateWrapper:更新场景

场景:使用 Lambda 风格更新用户名包含 "a" 且(年龄 < 24 或邮箱为 null)的用户。

@Test
public void testLambdaUpdateWrapper() {LambdaUpdateWrapper<People> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();lambdaUpdateWrapper.set(People::getAge, 18).set(People::getEmail, "people@qcby.com").like(People::getName, "a").and(i -> i.lt(People::getAge, 24).or().isNull(People::getEmail));int rows = peopleMapper.update(null, lambdaUpdateWrapper);System.out.println("受影响的行数:" + rows);
}

生成的 SQL

UPDATE t_people SET age=?, email=? 
WHERE is_deleted=0 
AND (username LIKE ? AND (age < ? OR email IS NULL))

http://www.dtcms.com/a/300293.html

相关文章:

  • 定义域第一题
  • iview: 对输入框进行Poptip 换行提示
  • python---元组解包(Tuple Unpacking)
  • 银行营销数据预测分析:从数据到精准营销决策
  • 表征工程 中怎么 调整参数或比例
  • 【RHCSA 问答题】第 13 章 访问 Linux 文件系统
  • 水下目标识别准确率↑89%!陌讯多模态融合算法在智慧水务的落地实践
  • ArkData-关系型数据库
  • 测试分类
  • Swagger 配置及使用指南
  • Redis C++客户端——通用命令
  • 多模态大模型与 AI 落地:从技术原理到实践路径的深度解析
  • 力扣刷题(第九十九天)
  • 【C语言进阶】程序环境和预处理
  • [Python 基础课程]注释
  • C++高效实现AI人工智能实例
  • IntelliJ IDEA 中左上方未显示项目根目录问题
  • 网络:基础概念
  • GLSL 3.0简介
  • [RPA] 日期时间练习案例
  • Xinference vs SGLang:详细对比分析
  • 最优估计准则与方法(4)最小二乘估计(LS)_学习笔记
  • 【补题】Codeforces Global Round 15 B. Running for Gold
  • P1019 [NOIP 2000 提高组] 单词接龙
  • 从Python编程到AI大模型:GeoAI大模型驱动的地球科学智能计算——涵盖随机森林、CNN、LSTM、Transformer及科研绘图实战
  • linux mmc驱动精讲-1、引言
  • UNet改进(25):集成可变形注意力的高效图像分割方法
  • python 检测蜂窝网络,实现掉网自动拨号
  • nacos启动报错:Unable to start embedded Tomcat。
  • ChatIm项目文件上传与获取