This repository has been archived on 2025-06-28. You can view files and clone it, but cannot push or open issues or pull requests.
Files
vitepress-theme-blog-charle…/docs/courses/mybatis/02-MyBatis-Plus基础/04-条件构造器.md

644 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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<T> updateWrapper) : int`
- `delete(Wrapper<T> queryWrapper) : int`
- `selectOne(Wrapper<T> queryWrapper) : T`
- `selectCount(Wrapper<T> queryWrapper) : Integer`
- `selectList(Wrapper<T> queryWrapper) : List<T>`
- `selectMaps(Wrapper<T> queryWrapper) : List<Map<String, Object>>`
- `selectObjs(Wrapper<T> queryWrapper) : List<Object>`
- `selectPage(E page, Wrapper<T> queryWrapper) : E`
- `selectMapsPage(E page, Wrapper<T> 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<T> extends Mapper<T> {
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> 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<T>`
- ...
**测试代码:**
```java
@SpringBootTest
class MybatisPlusWrapperTests {
@Autowired
private UserMapper userMapper;
// 需求:查询用户的姓名和年龄信息
@Test
void testSelectList1() {
// 创建查询条件构造器对象,通过泛型指定查询结果类型
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 指定查询 name、age 两列数据
queryWrapper.select("name", "age");
// 执行用户列表查询
List<User> 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<User> 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 | eqequal |
| <> 或 != | 不等于 | ne(R column, Object val) : Children | nenot equal |
| > | 大于 | gt(R column, Object val) : Children | gtgreater than |
| < | 小于 | lt(R column, Object val) : Children | ltless than |
| >= | 大于等于 | ge(R column, Object val) : Children | gegreater than or equal |
| <= | 小于等于 | le(R column, Object val) : Children | leless 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<User> queryWrapper = new QueryWrapper<>();
// gegreater equals 大于等于
queryWrapper.ge("age", 21);
// 执行用户列表查询
List<User> 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\<Param> consumer) : Children |
| **OR** | 逻辑或,只要一个为真,则结果为真 | or() : Children |
| | 嵌套 or | or(Consumer\<Param> consumer) : Children |
| **NOT** | 逻辑非,若操作数为假,结果则为真 | not(Consumer\<Param> consumer) : Children |
**测试代码:**
```java
@SpringBootTest
class MybatisPlusWrapperTests {
@Autowired
private UserMapper userMapper;
// 需求:查询年龄 >= 21 并且姓名为Tom的用户数据
@Test
void testSelectList3() {
// 创建查询条件构造器对象,通过泛型指定查询结果类型
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 可以分开设置
// queryWrapper.ge("age", 21);
// queryWrapper.eq("name", "Tom");
// 也可以链式操作
queryWrapper.ge("age", 21)
.eq("name", "Tom");
// 执行用户列表查询
List<User> 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<User> queryWrapper = new QueryWrapper<>();
// 或者关系
queryWrapper.eq("age", 18)
.or()
.eq("age", 24);
// 执行用户列表查询
List<User> 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<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "o")
.or(i -> i.eq("age", 21).likeRight("name", "S"));
// 执行用户列表查询
List<User> 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<User> queryWrapper = new QueryWrapper<>();
// 如果是对相同列的多个值查询使用in查询优化
queryWrapper.in("age", 18, 24);
// 执行用户列表查询
List<User> 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<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "o");
// 执行用户列表查询
List<User> 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) &gt; 10") 例2having("sum(age) &gt; {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<User> queryWrapper = new LambdaQueryWrapper<>();
// Lambda 语法无需再担心字段写错
queryWrapper.ge(User::getAge, 21);
// 执行用户列表查询
List<User> 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<User> queryWrapper = new QueryWrapper<>();
// 模拟一个封装好查询条件的 Map 集合
Map<String, Object> map = new HashMap<>();
map.put("age", 28);
map.put("name", "Tom");
// 将Map直接传给Wrapper的allEq方法它会自行识别查询条件
queryWrapper.allEq(map);
// 执行用户列表查询
List<User> 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 和 配置让自己能用起来,最后熟练使用的基础上,在空闲时尝试阅读它的源码让自己能够洞彻它的运行机制,部分问题出现的原因,同时借鉴这些技术实现来提升自己的代码高度。
所以在笔者的文章中,前期基本都是小白文,仅仅穿插很少量的源码研究。当然等小白文更新多了,你们还依然喜欢,后期会不定时专门对部分技术的源码进行解析。
:::