diff --git a/docs/courses/mybatis/02-MyBatis-Plus基础/04-条件构造器.md b/docs/courses/mybatis/02-MyBatis-Plus基础/04-条件构造器.md new file mode 100644 index 000000000..b2e7fe901 --- /dev/null +++ b/docs/courses/mybatis/02-MyBatis-Plus基础/04-条件构造器.md @@ -0,0 +1,643 @@ +--- +title: 条件构造器 +author: 查尔斯 +date: 2021/01/24 13:50 +categories: + - MyBatis-Plus快速入门 +tags: + - MyBatis-Plus + - MyBatis + - ORM框架 +--- + +# 条件构造器 + +## 前言 + +**C:** 在前两篇 MP 的 CRUD API 演示中,笔者一直刻意忽略了一些带有条件构造器的 API,你说哪些是带有条件构造器的 API ?看下面。 + +- `update(T entity, Wrapper updateWrapper) : int` +- `delete(Wrapper queryWrapper) : int` +- `selectOne(Wrapper queryWrapper) : T` +- `selectCount(Wrapper queryWrapper) : Integer` +- `selectList(Wrapper queryWrapper) : List` +- `selectMaps(Wrapper queryWrapper) : List>` +- `selectObjs(Wrapper queryWrapper) : List` +- `selectPage(E page, Wrapper queryWrapper) : E` +- `selectMapsPage(E page, Wrapper queryWrapper) : E` + +看到了吧?上述这些 API 中,都有一个显著的特点,即要求传递一个 Wrapper 类型的参数,而这个 Wrapper 类型就是笔者提到的条件构造器。 + +预热了两篇之久,本篇,笔者将带着你入门 MP 的条件构造器,看看传统的 SQL 语句条件如何用 条件构造器API 组装出来。 + +![202101241302860](../../../public/img/2021/01/24/202101241302860.jpg) + +## 概述 + +Wrapper 类型,顾名思义就是一个包装类,但它又不是我们常说的 Integer 这种包装类概念,在 MP 中它是用于包装各种丰富的查询条件的包装类。 + +它是 MP 中条件包装类的顶级类,笔者在下方给你列出了它的类层次结构。当然,枝繁叶茂的它不可能就这几个子类,笔者只不过是挑重点的展示一下而已。 + +![202101241303960.](../../../public/img/2021/01/24/202101241303960.png) + +但Wrapper 类是一个抽象类,所以我们不可能直接使用它,而是需要使用它的子类,那么哪些子类是我们常用的呢?一共有4个。 + +- `QueryWrapper`:查询条件构造器 + +- `UpdateWrapper`:更新条件构造器 +- `LambdaQueryWrapper`:使用 Lambda 语法的查询条件构造器 +- `LambdaUpdateWrapper`:使用 Lambda 语法的更新条件构造器 + +接下来笔者就以 `QueryWrapper` 和 `LambdaQueryWrapper` 为例,带着大家体验一下条件构造器。至于其他两个,使用方法没有太大差别,所以笔者不再单独讲解了。 + +我们还是先CV一个专用于条件构造器的单元测试类。 + +![202101241303970](../../../public/img/2021/01/24/202101241303970.gif) + +## QueryWrapper + +QueryWrapper 是 MP 中主要用于查询操作的条件包装类,我们将借助《快速入门》篇提到过的查询实体列表 API 来测试一下它。 + +```java +// 其他 API 略 +public interface BaseMapper extends Mapper { + + /** + * 根据 entity 条件,查询全部记录 + * + * @param queryWrapper 实体对象封装操作类(可以为 null) + */ + List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + +} +``` + +下方的基础 SQL 查询语法,大家应该都不陌生吧? + +```sql +SELECT + [ALL | DISTINCT] -- 是否去重 + {* | table_name.* | [table_name.field1 [AS alias1] [, table_name.field2 [AS alias2]][, ...]]} -- 查询哪些列 +FROM + table_name [AS table_ alias] [, ...] -- 从哪些表查询 + [LEFT | RIGHT | INNER JOIN table_name2 [AS table_alias] ON 关联条件] -- 连接查询 +[WHERE ...] -- 根据条件来完成上述表数据的筛选 +[GROUP BY …] -- 根据一个或多个列分组 +[HAVING …] -- 分组查询后的筛选条件 +[ORDER BY… ] -- 根据一个或多个列排序 +[LIMIT {[offset,] row_count}] -- 限制查询结果数量和范围 +``` + +笔者就是要以 QueryWrapper ,带大家体验一下如何用条件构造器,来实现上述的基础 SQL 查询。 + +### 指定查询的列 + +在写查询类 SQL 时,我们都要先指定好要查询哪些列。在 MP 的查询条件构造器中,可以通过 `select()` 方法来实现查询列的指定。 + +- `select(String... columns) : QueryWrapper` +- ... + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询用户的姓名和年龄信息 + @Test + void testSelectList1() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + QueryWrapper queryWrapper = new QueryWrapper<>(); + // 指定查询 name、age 两列数据 + queryWrapper.select("name", "age"); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } +} +``` + +**控制台输出:** + +```java +==> Preparing: SELECT name,age FROM user WHERE is_delete=0 +==> Parameters: +<== Columns: name, age +<== Row: Jone, 18 +<== Row: Jack, 20 +<== Row: Tom, 28 +<== Row: Sandy, 21 +<== Row: Billie, 24 +<== Total: 5 +``` + +``` +User(id=null, name=Jone, age=18, email=null, createTime=null, updateTime=null, isDelete=null) +User(id=null, name=Jack, age=20, email=null, createTime=null, updateTime=null, isDelete=null) +User(id=null, name=Tom, age=28, email=null, createTime=null, updateTime=null, isDelete=null) +User(id=null, name=Sandy, age=21, email=null, createTime=null, updateTime=null, isDelete=null) +User(id=null, name=Billie, age=24, email=null, createTime=null, updateTime=null, isDelete=null) +``` + +而且,你还可以借助这个方法实现结果去重功能,只需要在第一个指定的列名前添加 `DISTINCT` 关键字即可。 + +```java +// 创建查询条件构造器对象,通过泛型指定查询结果类型 +QueryWrapper queryWrapper = new QueryWrapper<>(); +// 指定查询 name、age 两列数据,并去重结果 +queryWrapper.select("DISTINCT name", "age"); +``` + +最终执行的 SQL 就变成了这样: + +```sql +SELECT DISTINCT name,age FROM user WHERE is_delete=0 +``` + +::: tip 笔者说 +聪明如你,一定能举一反三,如果未来需要给查询列起别名、或者使用一些聚合函数,直接在 select() 方法中写就可以。 +::: + +### where条件子句 + +查询类 SQL 中,在指定了查询哪些列之后,另一个非常重要的就是指定筛选结果数据的条件。 + +where 条件子句就是 **用于检索数据表中符合条件记录** 的,**条件子句可以由一个或多个逻辑表达式组成,结果一般为真或假。** + +#### 关系运算符 + +下方是 where 条件子句中常用关系运算 和 MP 中对应方法的对照表。 + +| **SQL 运算符** | **含义** | **MP 对应方法** | 笔者帮你强化理解 | +| -------------- | :------------- | ----------------- | -------------- | +| = | 等于 | eq(R column, Object val) : Children | eq:equal | +| <> 或 != | 不等于 | ne(R column, Object val) : Children | ne:not equal | +| > | 大于 | gt(R column, Object val) : Children | gt:greater than | +| < | 小于 | lt(R column, Object val) : Children | lt:less than | +| >= | 大于等于 | ge(R column, Object val) : Children | ge:greater than or equal | +| <= | 小于等于 | le(R column, Object val) : Children | le:less than or equal | +| is null | 等于null | isNull(R column) : Children | | +| is not null | 不等于null | isNotNull(R column) : Children | | + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询年龄 >= 21 的用户数据 + @Test + void testSelectList2() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + QueryWrapper queryWrapper = new QueryWrapper<>(); + // ge:greater equals 大于等于 + queryWrapper.ge("age", 21); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } + +} +``` + +**控制台输出:** + +```sql +==> Preparing: SELECT id,name,age,email,create_time,update_time,is_delete FROM user WHERE is_delete=0 AND (age >= ?) +==> Parameters: 21(Integer) +<== Columns: id, name, age, email, create_time, update_time, is_delete +<== Row: 3, Tom, 28, Tom@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 4, Sandy, 21, Sandy@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 5, Billie, 24, Billie@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Total: 3 +``` + +``` +User(id=3, name=Tom, age=28, email=Tom@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=4, name=Sandy, age=21, email=Sandy@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=5, name=Billie, age=24, email=Billie@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +``` + +其他的笔者就不再测试了,你可以自己挨个试试。 + +#### 逻辑运算符 + +##### 普通逻辑 + +| **SQL 运算符** | **含义** | **MP 对应方法** | +| -------------- | :------------------------------- | ----------------------------------------- | +| **AND** | 逻辑与,同时为真,结果才为真 | 默认使用 and 作为多个条件之间的关系表示 | +| | 嵌套 and | and(Consumer\ consumer) : Children | +| **OR** | 逻辑或,只要一个为真,则结果为真 | or() : Children | +| | 嵌套 or | or(Consumer\ consumer) : Children | +| **NOT** | 逻辑非,若操作数为假,结果则为真 | not(Consumer\ consumer) : Children | + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询年龄 >= 21 并且姓名为Tom的用户数据 + @Test + void testSelectList3() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + QueryWrapper queryWrapper = new QueryWrapper<>(); + // 可以分开设置 + // queryWrapper.ge("age", 21); + // queryWrapper.eq("name", "Tom"); + // 也可以链式操作 + queryWrapper.ge("age", 21) + .eq("name", "Tom"); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } + +} +``` + +**控制台输出:** + +```sql +==> Preparing: SELECT id,name,age,email,create_time,update_time,is_delete FROM user WHERE is_delete=0 AND (age >= ? AND name = ?) +==> Parameters: 21(Integer), Tom(String) +<== Columns: id, name, age, email, create_time, update_time, is_delete +<== Row: 3, Tom, 28, Tom@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Total: 1 +``` + +``` +User(id=3, name=Tom, age=28, email=Tom@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +``` + +当你编写了多个条件表达式的时候,MP 默认认为它们之间采用 `and` 关系。但如果你想实现 `or` 关系的需求,那就必须得使用 `or()` 方法了。 + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询年龄 = 18 或者 年龄 = 24 的用户数据 + @Test + void testSelectList4() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + QueryWrapper queryWrapper = new QueryWrapper<>(); + // 或者关系 + queryWrapper.eq("age", 18) + .or() + .eq("age", 24); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } + +} +``` + +**控制台输出:** + +```sql +==> Preparing: SELECT id,name,age,email,create_time,update_time,is_delete FROM user WHERE is_delete=0 AND (age = ? OR age = ?) +==> Parameters: 18(Integer), 24(Integer) +<== Columns: id, name, age, email, create_time, update_time, is_delete +<== Row: 1, Jone, 18, Jone@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 5, Billie, 24, Billie@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Total: 2 +``` + +``` +User(id=1, name=Jone, age=18, email=Jone@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=5, name=Billie, age=24, email=Billie@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +``` + +##### 嵌套逻辑 + +我们看到上方的对照表中,还有一种是用于嵌套 or 或 嵌套 and 关系的方法,有些同学可能有点懵,看看下面这行代码是不是就明白了呢? + +```sql +select xx from xx where xx = xx or (xx = xx and xx = xx) +``` + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询姓名中带有o字母 或者 (年龄 = 21 并且 姓名以S字母开头) 的用户数据 + @Test + void testSelectList7() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.like("name", "o") + .or(i -> i.eq("age", 21).likeRight("name", "S")); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } + +} +``` + +**控制台输出:** + +```sql +==> Preparing: SELECT id,name,age,email,create_time,update_time,is_delete FROM user WHERE is_delete=0 AND (name LIKE ? OR (age = ? AND name LIKE ?)) +==> Parameters: %o%(String), 21(Integer), S%(String) +<== Columns: id, name, age, email, create_time, update_time, is_delete +<== Row: 1, Jone, 18, Jone@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 3, Tom, 28, Tom@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 4, Sandy, 21, Sandy@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Total: 3 +``` + +``` +User(id=1, name=Jone, age=18, email=Jone@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=3, name=Tom, age=28, email=Tom@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=4, name=Sandy, age=21, email=Sandy@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +``` + +#### 范围查询 + +上面的 `or` 关系需求中,是对相同列的多个值的查询,这种情况在 SQL 中我们可以采用 in 查询来优化。而如果是对相同列的连续范围值的查询,则可以采用 between ... and ...查询来优化。 + +下方是 in 查询 和 between ... and ...查询与 MP 中方法的对照表。 + +| **SQL 运算符** | **含义** | **MP 对应方法** | +| ----------------------- | :--------------- | --------------------------------------------------------- | +| in (值1, 值2, ...) | 在某个列表之间 | in(R column, Object... values) : Children | +| not in (值1, 值2, ...) | 不在某个列表之间 | notIn(R column, Object... value) : Children | +| between ... and ... | 在某个范围之间 | between(R column, Object val1, Object val2) : Children | +| not between ... and ... | 不在某个范围之间 | notBetween(R column, Object val1, Object val2) : Children | + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询年龄 = 18 或者 年龄 = 24 的用户数据 + @Test + void testSelectList5() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + QueryWrapper queryWrapper = new QueryWrapper<>(); + // 如果是对相同列的多个值查询,使用in查询优化 + queryWrapper.in("age", 18, 24); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } + +} +``` + +**控制台输出:** + +```sql +==> Preparing: SELECT id,name,age,email,create_time,update_time,is_delete FROM user WHERE is_delete=0 AND (age IN (?,?)) +==> Parameters: 18(Integer), 24(Integer) +<== Columns: id, name, age, email, create_time, update_time, is_delete +<== Row: 1, Jone, 18, Jone@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 5, Billie, 24, Billie@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Total: 2 +``` + +``` +User(id=1, name=Jone, age=18, email=Jone@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=5, name=Billie, age=24, email=Billie@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +``` + +#### 模糊查询 + +除了精确的查询之外, 模糊查询也是使用频率很高的。下方是模糊查询 和 MP 中方法的对照表。 + +| **SQL 运算符** | **含义** | **MP 对应方法** | +| -------------- | :--------------- | ------------------------------------------ | +| like '%A%' | 在某个范围之间 | like(R column, Object val) : Children | +| not like '%A%' | 不在某个范围之间 | notLike(R column, Object val) : Children | +| like '%A' | 查询 | likeLeft(R column, Object val) : Children | +| like 'A%' | 不在某个列表之间 | likeRight(R column, Object val) : Children | + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询姓名中带有 o 字母的用户数据 + @Test + void testSelectList6() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.like("name", "o"); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } + +} +``` + +**控制台输出:** + +```sql +==> Preparing: SELECT id,name,age,email,create_time,update_time,is_delete FROM user WHERE is_delete=0 AND (name LIKE ?) +==> Parameters: %o%(String) +<== Columns: id, name, age, email, create_time, update_time, is_delete +<== Row: 1, Jone, 18, Jone@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 3, Tom, 28, Tom@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Total: 2 +``` + +``` +User(id=1, name=Jone, age=18, email=Jone@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=3, name=Tom, age=28, email=Tom@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +``` + +### 分组查询 + +好了,写了这么多个查询示例,笔者相信聪明的你已经悟了。我们本篇毕竟不是去讲解 SQL 语句的,所以笔者最后把分组查询和排序查询的 API 再列一下,你想测试就自行测试一下吧。 + +| **SQL 运算符** | **含义** | **MP 对应方法** | 示例 | +| ----------------- | :--------------------- | ----------------------------------------------------- | ------------------------------------------------------------ | +| group by 列1, 列2 | 根据一个列或多个列分组 | groupBy(R column) : Children | 例: groupBy("id", "name") | +| having ... | 分组查询后的筛选条件 | having(String sqlHaving, Object... params) : Children | 例1: having("sum(age) > 10") 例2:having("sum(age) > {0}", 10) | + +### 排序查询 + +| **SQL 运算符** | **含义** | **MP 对应方法** | 示例 | +| ---------------- | :--------------- | ------------------------------------ | ----------------------------- | +| order by 列 ASC | 按指定列升序排序 | orderByAsc(R... columns) : Children | 例: orderByAsc("id", "name") | +| order by 列 DESC | 按指定列降序排序 | orderByDesc(R... columns) : Children | 例: orderByDesc("id", "name") | + +### 连接查询 + +MP 的确很强大,但是它封装的接口都是针对单表的,所以如果我们要多表查询的时候,还是需要采用原生的 MyBatis 写法,这里笔者就不再介绍了。 + +## LambdaQueryWrapper + +LambdaQueryWrapper 和 QueryWrapper 只差一个 Lambda 语法的使用而已,不知道你是否还记得《快速入门》篇中介绍的 MP 特点,其中有一条就是:**支持 Lambda 形式调用** :通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错。[1] + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询年龄 >= 21 的用户数据 + @Test + void testSelectList8() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // Lambda 语法无需再担心字段写错 + queryWrapper.ge(User::getAge, 21); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } + +} +``` + +**控制台输出:** + +```sql +==> Preparing: SELECT id,name,age,email,create_time,update_time,is_delete FROM user WHERE is_delete=0 AND (age >= ?) +==> Parameters: 21(Integer) +<== Columns: id, name, age, email, create_time, update_time, is_delete +<== Row: 3, Tom, 28, Tom@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 4, Sandy, 21, Sandy@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Row: 5, Billie, 24, Billie@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Total: 3 +``` + +``` +User(id=3, name=Tom, age=28, email=Tom@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=4, name=Sandy, age=21, email=Sandy@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +User(id=5, name=Billie, age=24, email=Billie@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +``` + +## allEq + +最后,笔者再介绍一个比较实用的方法:`allEq`,当你得到的查询条件都被封装好在一个 Map 集合中时,为了使用 MP 查询这些条件,难道还要一个个的将数据取出来封装为 Wrapper 吗?显然我们是拒绝的。 + +`allEq` 可以解决此问题。 + +**测试代码:** + +```java +@SpringBootTest +class MybatisPlusWrapperTests { + + @Autowired + private UserMapper userMapper; + + // 需求:查询年龄 = 28 并且姓名为Tom的用户数据 + @Test + void testSelectList9() { + // 创建查询条件构造器对象,通过泛型指定查询结果类型 + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 模拟一个封装好查询条件的 Map 集合 + Map map = new HashMap<>(); + map.put("age", 28); + map.put("name", "Tom"); + + // 将Map直接传给Wrapper的allEq方法,它会自行识别查询条件 + queryWrapper.allEq(map); + + // 执行用户列表查询 + List userList = userMapper.selectList(queryWrapper); + + // 遍历用户列表 + userList.forEach(System.out::println); + } + +} +``` + +**控制台输出:** + +``` +==> Preparing: SELECT id,name,age,email,create_time,update_time,is_delete FROM user WHERE is_delete=0 AND (name = ? AND age = ?) +==> Parameters: Tom(String), 28(Integer) +<== Columns: id, name, age, email, create_time, update_time, is_delete +<== Row: 3, Tom, 28, Tom@126.com, 2021-01-23 17:47:52, 2021-01-23 17:47:52, 0 +<== Total: 1 +``` + +``` +User(id=3, name=Tom, age=28, email=Tom@126.com, createTime=2021-01-23T17:47:52, updateTime=2021-01-23T17:47:52, isDelete=0) +``` + +::: warning 笔者说 +需要注意的是 `allEq()` 方法 **只能用于具有 and 关系且都是等值判断的情况** 。 +::: + +## 参考文献 + +[1]MyBatis Plus 官网. 指南[EB/OL]. https://baomidou.com/guide/. 2021-01-18 + +## 后记 + +**C:** 好了,MP 的条件构造器就介绍完了。笔者有很多 API 没有带大家测试,但我想你也能明白,即便我全部测试了,它也不一定能被你用上,灵活使用它们是需要时间积累的。所以说,讲些典型的,让你 "悟了" MP 的大致规律和节奏,这才是最重要的。 + +除了 API 之外,实际上,MP 还有一些功能,因为时间原因,笔者在本次系列并没有提及,你可以前往官网查阅一下,或者等后面笔者时间允许的时候,会再去介绍下它的其他功能。 + +**最后的最后,笔者个人建议,在日常开发中,如果遇到的需求需要写一个比较复杂的 SQL,那还是直接使用 MyBatis 原生写法去 XML 中写吧,毕竟 MyBatis 最强大的优势还是体现在 XML 的 SQL 中。** + +::: info 笔者说 +对于技术的学习,笔者一贯遵循的步骤是:先用最最简单的 demo 让它跑起来,然后学学它的最最常用 API 和 配置让自己能用起来,最后熟练使用的基础上,在空闲时尝试阅读它的源码让自己能够洞彻它的运行机制,部分问题出现的原因,同时借鉴这些技术实现来提升自己的代码高度。 + +所以在笔者的文章中,前期基本都是小白文,仅仅穿插很少量的源码研究。当然等小白文更新多了,你们还依然喜欢,后期会不定时专门对部分技术的源码进行解析。 +::: diff --git a/docs/public/img/2021/01/24/202101241302860.jpg b/docs/public/img/2021/01/24/202101241302860.jpg new file mode 100644 index 000000000..296cad6a3 Binary files /dev/null and b/docs/public/img/2021/01/24/202101241302860.jpg differ diff --git a/docs/public/img/2021/01/24/202101241303960.png b/docs/public/img/2021/01/24/202101241303960.png new file mode 100644 index 000000000..2f9ecbb49 Binary files /dev/null and b/docs/public/img/2021/01/24/202101241303960.png differ diff --git a/docs/public/img/2021/01/24/202101241303970.gif b/docs/public/img/2021/01/24/202101241303970.gif new file mode 100644 index 000000000..f84042ea2 Binary files /dev/null and b/docs/public/img/2021/01/24/202101241303970.gif differ