程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • mybatis-plus

    • mybatis-plus概述
    • MyBatis-Plus入门案例
    • BaseMapper 增删改查
    • Service层 增删改查
    • MyBatis-Plus常用注解
    • MyBatis-Plus条件构造器
    • MyBatis-Plus查询条件
      • 1. 查询方式概述
      • 2. MyBatis-Plus查询方法总览
      • 3. 基础查询方法
        • 3.1 根据ID查询
        • 3.2 批量ID查询
        • 3.3 使用Map条件查询
        • 3.4 全表查询
        • 3.5 查询单条记录
      • 4. 使用不同类型对象作为查询条件
        • 4.1 使用实体对象查询
        • 4.2 使用Map对象查询
        • 4.3 使用自定义查询对象
      • 5. 条件构造器详解
        • 5.1 QueryWrapper基础用法
        • 5.2 条件优先级和分组
        • 5.3 动态条件查询
        • 5.4 子查询
        • 5.5 指定查询字段
      • 6. LambdaQueryWrapper:类型安全的查询构造器
        • 6.1 LambdaQueryWrapper动态条件查询
        • 6.2 LambdaQueryChainWrapper:链式调用增强
      • 7. 分页查询
        • 7.1 带排序的分页查询
        • 7.2 自定义分页查询
      • 8. 多表关联查询
      • 9. 常见查询场景示例
        • 9.1 组合查询条件
        • 9.2 模糊查询与精确查询结合
        • 9.3 区间查询
      • 10. 查询结果的映射规则
        • 1. 基础映射规则:只能映射到泛型指定的实体类
        • 2. 要使用VO/DTO等其他类型接收结果,必须自定义方法
      • 11. 查询条件构建最佳实践
        • 11.1 使用条件构造器的推荐方式
        • 11.2 条件构造器性能优化
        • 11.3 集中管理查询条件
      • 12. 常见查询问题与解决方案
        • 12.1 处理大数据量查询
        • 12.2 处理动态排序
        • 12.3 查询结果映射问题
      • 13. 高级查询技巧
        • 13.1 使用嵌套查询
        • 13.2 使用SQL函数和表达式
        • 13.3 使用EXISTS和NOT EXISTS
    • MyBatis-Plus常用插件
    • 通用枚举和多数据源
    • MyBatisX 插件
  • MyBatis-plus
  • mybatis-plus
scholar
2025-03-16
目录

MyBatis-Plus查询条件

# MyBatis-Plus查询条件

# 1. 查询方式概述

MyBatis-Plus提供了丰富的查询方式,可以满足各种复杂业务场景的需求。

# 2. MyBatis-Plus查询方法总览

MyBatis-Plus提供了丰富的查询方法,从简单到复杂,从单表到多表,几乎涵盖了所有常见的查询场景。下表列出了BaseMapper中提供的主要查询方法:

方法名 功能描述 参数说明 返回值
selectById 根据ID查询单条记录 主键ID 实体对象
selectBatchIds 根据ID集合批量查询 ID集合 实体对象列表
selectByMap 根据Map条件查询 列名-值映射的Map 实体对象列表
selectOne 根据条件查询单条记录 条件构造器 实体对象
selectList 根据条件查询多条记录 条件构造器 实体对象列表
selectCount 根据条件查询记录数 条件构造器 记录数
selectPage 根据条件分页查询 分页参数, 条件构造器 分页结果

# 3. 基础查询方法

# 3.1 根据ID查询

最简单的查询方式是根据主键ID查询单条记录:

/**
 * 根据ID查询单条记录
 * @param id 主键ID,必须是数据库表中的主键
 * @return 返回查询到的实体对象,如果未找到返回null
 */
@Test
public void testSelectById() {
    // 根据ID查询单条记录
    User user = userMapper.selectById(1L);
    
    // 输出查询结果
    System.out.println("查询结果: " + user);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3.2 批量ID查询

当需要根据多个ID查询多条记录时,可以使用批量ID查询方法:

/**
 * 批量ID查询示例
 * @param idList 主键ID集合,要查询的多个ID
 * @return 返回匹配ID的实体对象列表
 */
@Test
public void testSelectBatchIds() {
    // 创建要查询的ID列表
    List<Long> idList = Arrays.asList(1L, 2L, 3L);
    
    // 执行批量查询
    List<User> userList = userMapper.selectBatchIds(idList);
    
    // 输出查询结果
    System.out.println("共查询到 " + userList.size() + " 条记录");
    userList.forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 3.3 使用Map条件查询

MyBatis-Plus支持使用Map构建简单的查询条件:

/**
 * 使用Map构建查询条件
 * Map中的key为数据库列名,value为查询条件的值
 * 多个条件之间是AND关系
 */
@Test
public void testSelectByMap() {
    // 创建查询条件Map
    Map<String, Object> columnMap = new HashMap<>();
    
    // 添加条件:age=25 AND name='张三'
    columnMap.put("age", 25);
    columnMap.put("name", "张三");
    
    // 执行查询
    List<User> userList = userMapper.selectByMap(columnMap);
    
    // 输出查询结果
    System.out.println("共查询到 " + userList.size() + " 条记录");
    userList.forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

注意事项:

  • Map中的key必须是数据库表中的列名,而不是实体类的属性名
  • Map条件之间是AND关系,无法实现OR等复杂查询
  • 仅支持等值查询,不支持大于、小于、LIKE等复杂条件

# 3.4 全表查询

在某些场景下,可能需要查询表中的所有数据:

/**
 * 全表查询示例
 * 查询表中的所有记录,适用于数据量较小的表
 * 数据量大时应避免使用此方法,改用分页查询
 */
@Test
public void testSelectAll() {
    // 传入null表示没有条件,即查询所有记录
    List<User> userList = userMapper.selectList(null);
    
    // 输出查询结果
    System.out.println("总记录数: " + userList.size());
    userList.forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.5 查询单条记录

当需要查询满足条件的单条记录时,可以使用selectOne方法:

/**
 * 查询单条记录示例
 * 当查询结果多于一条时会抛出异常
 */
@Test
public void testSelectOne() {
    // 创建查询条件
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("username", "admin");  // 查询用户名为admin的记录
    
    // 执行查询
    User user = userMapper.selectOne(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果: " + user);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

注意事项:

  • 当查询结果为多条时,会抛出TooManyResultsException异常
  • 建议在唯一索引字段上使用此方法
  • 可以使用last方法限制结果数量:queryWrapper.last("LIMIT 1")

# 4. 使用不同类型对象作为查询条件

MyBatis-Plus提供了多种方式使用不同类型的对象作为查询条件,每种方式都有其适用场景。

# 4.1 使用实体对象查询

可以直接使用实体对象作为查询条件,非空属性将作为等值查询条件:

/**
 * 使用实体对象作为查询条件
 * 实体类中的非空属性将作为等值查询条件,多个条件之间是AND关系
 */
@Test
public void testEntityQuery() {
    // 创建实体对象并设置查询条件
    User queryUser = new User();
    queryUser.setAge(25);  // 年龄=25
    queryUser.setGender("男");  // 性别=男
    
    // 执行查询(两种方式)
    // 方式1:使用实体对象构造QueryWrapper
    List<User> list1 = userMapper.selectList(new QueryWrapper<>(queryUser));
    
    // 方式2:使用实体对象直接作为allEq的参数
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.allEq(BeanUtil.beanToMap(queryUser));
    List<User> list2 = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + list1.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

注意事项:

  • 只有非空属性会被作为查询条件
  • 实体对象查询仅支持等值查询,不支持其他比较操作
  • 使用的是属性名而非列名,会自动进行驼峰转换

# 4.2 使用Map对象查询

使用Map构建查询条件更加灵活:

/**
 * 使用Map构建查询条件示例
 * Map的key为列名,value为查询值
 */
@Test
public void testMapQuery() {
    // 创建查询条件Map
    Map<String, Object> columnMap = new HashMap<>();
    columnMap.put("age", 25);  // 年龄=25
    columnMap.put("gender", "男");  // 性别=男
    
    // 执行查询
    List<User> userList = userMapper.selectByMap(columnMap);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注意事项:

  • Map中使用的key是数据库列名而非属性名
  • 支持在key中使用列的别名(如果查询时指定了别名)
  • 不支持复杂条件,只能是等值查询

# 4.3 使用自定义查询对象

在复杂业务场景中,通常需要使用自定义查询对象来封装查询条件:

/**
 * 自定义查询对象
 * 用于封装复杂查询条件,提高代码可读性和可维护性
 */
@Data
public class UserQuery {
    private String name;  // 用户名(模糊查询)
    private Integer minAge;  // 最小年龄
    private Integer maxAge;  // 最大年龄
    private List<String> statusList;  // 状态列表
    private Date startDate;  // 开始日期
    private Date endDate;  // 结束日期
    private Boolean sortByAge;  // 是否按年龄排序
}

/**
 * 使用自定义查询对象构建查询条件示例
 */
@Test
public void testCustomQueryObject() {
    // 创建自定义查询对象
    UserQuery query = new UserQuery();
    query.setName("张");  // 用户名包含"张"
    query.setMinAge(20);  // 年龄>=20
    query.setMaxAge(30);  // 年龄<=30
    query.setStatusList(Arrays.asList("active", "pending"));  // 状态in ('active','pending')
    query.setStartDate(DateUtil.parseDate("2023-01-01"));  // 创建日期>=2023-01-01
    query.setEndDate(DateUtil.parseDate("2023-12-31"));  // 创建日期<=2023-12-31
    query.setSortByAge(true);  // 按年龄排序
    
    // 创建QueryWrapper并设置查询条件
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    // 动态添加查询条件
    if (StringUtils.isNotBlank(query.getName())) {
        queryWrapper.like("name", query.getName());
    }
    if (query.getMinAge() != null) {
        queryWrapper.ge("age", query.getMinAge());
    }
    if (query.getMaxAge() != null) {
        queryWrapper.le("age", query.getMaxAge());
    }
    if (CollectionUtils.isNotEmpty(query.getStatusList())) {
        queryWrapper.in("status", query.getStatusList());
    }
    if (query.getStartDate() != null) {
        queryWrapper.ge("create_time", query.getStartDate());
    }
    if (query.getEndDate() != null) {
        queryWrapper.le("create_time", query.getEndDate());
    }
    // 动态排序
    if (Boolean.TRUE.equals(query.getSortByAge())) {
        queryWrapper.orderByAsc("age");
    } else {
        queryWrapper.orderByDesc("create_time");
    }
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

优势:

  • 代码结构清晰,查询条件集中管理
  • 支持复杂的组合条件和动态查询
  • 可重用,多个位置可使用相同的查询对象
  • 可以添加业务验证逻辑

# 5. 条件构造器详解

条件构造器是MyBatis-Plus最强大的特性之一,它提供了丰富的API来构建复杂的查询条件。

# 5.1 QueryWrapper基础用法

QueryWrapper用于构建查询条件,支持各种比较操作和复杂条件组合:

/**
 * QueryWrapper基础用法示例
 * 展示常用的条件构建方法
 */
@Test
public void testQueryWrapperBasic() {
    // 创建QueryWrapper对象
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
    // 1. 等值条件
    queryWrapper.eq("status", "active");  // status = 'active'
    
    // 2. 不等条件
    queryWrapper.ne("gender", "女");  // gender != '女'
    
    // 3. 大于、小于条件
    queryWrapper.gt("age", 18);  // age > 18
    queryWrapper.lt("age", 60);  // age < 60
    
    // 4. 大于等于、小于等于条件
    queryWrapper.ge("credit_score", 700);  // credit_score >= 700
    queryWrapper.le("login_attempts", 5);  // login_attempts <= 5
    
    // 5. LIKE条件
    queryWrapper.like("name", "张");  // name LIKE '%张%'
    queryWrapper.likeLeft("email", "gmail.com");  // email LIKE '%gmail.com'
    queryWrapper.likeRight("username", "admin");  // username LIKE 'admin%'
    
    // 6. 范围条件
    queryWrapper.between("age", 20, 30);  // age BETWEEN 20 AND 30
    queryWrapper.notBetween("login_time", "09:00", "18:00");  // login_time NOT BETWEEN '09:00' AND '18:00'
    
    // 7. IN条件
    queryWrapper.in("status", Arrays.asList("active", "pending"));  // status IN ('active', 'pending')
    queryWrapper.notIn("role", Arrays.asList("guest", "temp"));  // role NOT IN ('guest', 'temp')
    
    // 8. NULL条件
    queryWrapper.isNull("delete_time");  // delete_time IS NULL
    queryWrapper.isNotNull("email");  // email IS NOT NULL
    
    // 9. 排序
    queryWrapper.orderByDesc("create_time");  // ORDER BY create_time DESC
    queryWrapper.orderByAsc("age");  // ORDER BY age ASC
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# 5.2 条件优先级和分组

在复杂查询中,可能需要控制条件的优先级和分组:

/**
 * 条件优先级和分组示例
 * 使用嵌套条件构建复杂查询
 */
@Test
public void testQueryWrapperGroup() {
    // 创建QueryWrapper对象
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
    // 构建条件: (status = 'active' OR status = 'pending') AND (age > 18 AND gender = '男')
    queryWrapper
        // 第一组条件,使用OR连接
        .and(wrapper -> wrapper
            .eq("status", "active")
            .or()
            .eq("status", "pending")
        )
        // 第二组条件,AND连接
        .and(wrapper -> wrapper
            .gt("age", 18)
            .eq("gender", "男")
        );
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 5.3 动态条件查询

在实际应用中,查询条件通常是由用户输入决定的,需要动态构建:

/**
 * 动态条件查询示例
 * 根据用户输入动态构建查询条件
 */
@Test
public void testDynamicCondition() {
    // 模拟用户输入的查询参数(可能为null)
    String name = "张";  // 可能为null
    Integer minAge = 20;  // 可能为null
    Integer maxAge = 30;  // 可能为null
    String status = null;  // 用户未选择状态条件
    
    // 创建QueryWrapper对象
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
    // 使用condition参数控制条件是否加入查询
    queryWrapper
        .like(StringUtils.isNotBlank(name), "name", name)  // 当name不为空时,添加LIKE条件
        .ge(minAge != null, "age", minAge)  // 当minAge不为空时,添加大于等于条件
        .le(maxAge != null, "age", maxAge)  // 当maxAge不为空时,添加小于等于条件
        .eq(StringUtils.isNotBlank(status), "status", status);  // 当status不为空时,添加等值条件
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 5.4 子查询

MyBatis-Plus支持构建子查询:

/**
 * 子查询示例
 * 使用子查询构建更复杂的查询条件
 */
@Test
public void testSubQuery() {
    // 创建QueryWrapper对象
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
    // 使用IN子查询:查询部门ID在活跃部门列表中的用户
    queryWrapper.inSql("department_id", "SELECT id FROM department WHERE status = 'active'");
    
    // 使用EXISTS子查询:查询有订单记录的用户
    queryWrapper.exists("SELECT 1 FROM order WHERE order.user_id = user.id AND order.status = 'completed'");
    
    // 使用自定义条件:查询消费金额大于平均值的用户
    queryWrapper.apply("consume_amount > (SELECT AVG(consume_amount) FROM user)");
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 5.5 指定查询字段

可以使用select方法指定要查询的字段,减少数据传输量:

/**
 * 指定查询字段示例
 * 只查询需要的字段,提高查询效率
 */
@Test
public void testSelectFields() {
    // 创建QueryWrapper对象
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
    // 指定要查询的字段
    queryWrapper.select("id", "name", "age", "email");
    
    // 添加查询条件
    queryWrapper.gt("age", 18);
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 6. LambdaQueryWrapper:类型安全的查询构造器

LambdaQueryWrapper是QueryWrapper的增强版,它使用Lambda表达式引用实体类的方法,避免硬编码字段名称,从而提供类型安全的查询:

/**
 * LambdaQueryWrapper基础用法示例
 * 使用Lambda表达式引用实体类字段,避免字符串硬编码
 */
@Test
public void testLambdaQueryWrapper() {
    // 创建LambdaQueryWrapper对象
    LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
    
    // 构建查询条件
    lambdaQuery
        .eq(User::getStatus, "active")  // status = 'active'
        .ge(User::getAge, 18)  // age >= 18
        .like(User::getName, "张")  // name LIKE '%张%'
        .orderByDesc(User::getCreateTime);  // ORDER BY create_time DESC
    
    // 执行查询
    List<User> userList = userMapper.selectList(lambdaQuery);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 6.1 LambdaQueryWrapper动态条件查询

LambdaQueryWrapper同样支持动态条件查询:

/**
 * LambdaQueryWrapper动态条件查询示例
 * 结合Lambda表达式和condition参数实现动态查询
 */
@Test
public void testLambdaQueryWrapperDynamic() {
    // 模拟用户输入的查询参数
    String name = "张";  // 可能为null
    Integer minAge = 20;  // 可能为null
    Integer maxAge = 30;  // 可能为null
    
    // 创建LambdaQueryWrapper对象
    LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
    
    // 构建动态查询条件
    lambdaQuery
        .like(StringUtils.isNotBlank(name), User::getName, name)  // 当name不为空时,添加LIKE条件
        .ge(minAge != null, User::getAge, minAge)  // 当minAge不为空时,添加大于等于条件
        .le(maxAge != null, User::getAge, maxAge)  // 当maxAge不为空时,添加小于等于条件
        .orderByDesc(User::getCreateTime);  // 按创建时间降序排序
    
    // 执行查询
    List<User> userList = userMapper.selectList(lambdaQuery);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 6.2 LambdaQueryChainWrapper:链式调用增强

MyBatis-Plus提供了更加便捷的链式调用封装:

/**
 * LambdaQueryChainWrapper示例
 * 进一步简化链式调用
 */
@Test
public void testLambdaQueryChainWrapper() {
    // 使用链式调用直接执行查询
    List<User> userList = new LambdaQueryChainWrapper<User>(userMapper)
        .like(User::getName, "张")
        .gt(User::getAge, 18)
        .orderByDesc(User::getCreateTime)
        .list();  // 直接获取结果列表
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 7. 分页查询

MyBatis-Plus提供了强大的分页查询功能,可以轻松实现数据分页:

/**
 * 基本分页查询示例
 * 演示如何使用MyBatis-Plus的分页功能
 */
@Test
public void testPageQuery() {
    // 创建分页对象,指定当前页和每页大小
    // 参数1:当前页码(从1开始)
    // 参数2:每页记录数
    Page<User> page = new Page<>(1, 10);
    
    // 创建查询条件
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.gt("age", 18);  // 年龄大于18
    
    // 执行分页查询
    Page<User> userPage = userMapper.selectPage(page, queryWrapper);
    
    // 获取分页结果
    List<User> records = userPage.getRecords();  // 当前页数据列表
    long total = userPage.getTotal();  // 总记录数
    long pages = userPage.getPages();  // 总页数
    long current = userPage.getCurrent();  // 当前页码
    long size = userPage.getSize();  // 每页大小
    
    // 输出分页信息
    System.out.println("总记录数: " + total);
    System.out.println("总页数: " + pages);
    System.out.println("当前页: " + current);
    System.out.println("每页记录数: " + size);
    System.out.println("当前页数据: ");
    records.forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 7.1 带排序的分页查询

可以在分页查询中添加排序条件:

/**
 * 带排序的分页查询示例
 * 在分页查询中添加排序条件
 */
@Test
public void testPageWithSort() {
    // 创建分页对象
    Page<User> page = new Page<>(1, 10);
    
    // 设置排序
    page.addOrder(OrderItem.desc("create_time"));  // 按创建时间降序
    page.addOrder(OrderItem.asc("age"));  // 再按年龄升序
    
    // 创建查询条件
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.gt(User::getAge, 18);
    
    // 执行分页查询
    Page<User> userPage = userMapper.selectPage(page, queryWrapper);
    
    // 输出分页结果
    userPage.getRecords().forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 7.2 自定义分页查询

在复杂业务场景中,可能需要自定义分页查询SQL:

/**
 * 自定义SQL的分页查询
 * 在Mapper接口中定义
 */
public interface UserMapper extends BaseMapper<User> {
    /**
     * 自定义分页查询
     * 注意:Page对象必须是第一个参数
     * @param page 分页参数
     * @param status 状态条件
     * @param minAge 最小年龄
     * @return 分页结果
     */
    Page<UserVO> selectUserVOPage(Page<UserVO> page, @Param("status") String status, @Param("minAge") Integer minAge);
}

/**
 * UserMapper.xml中定义对应的SQL
 */
/* XML配置
<select id="selectUserVOPage" resultType="com.example.vo.UserVO">
    SELECT 
        u.id, u.name, u.age, u.email, d.dept_name
    FROM 
        user u
    LEFT JOIN 
        department d ON u.dept_id = d.id
    <where>
        <if test="status != null and status != ''">
            AND u.status = #{status}
        </if>
        <if test="minAge != null">
            AND u.age >= #{minAge}
        </if>
    </where>
    ORDER BY u.id DESC
</select>
*/

/**
 * 调用自定义分页查询
 */
@Test
public void testCustomPageQuery() {
    // 创建分页对象
    Page<UserVO> page = new Page<>(1, 10);
    
    // 设置查询参数
    String status = "active";
    Integer minAge = 18;
    
    // 执行自定义分页查询
    Page<UserVO> userVOPage = userMapper.selectUserVOPage(page, status, minAge);
    
    // 输出分页结果
    System.out.println("总记录数: " + userVOPage.getTotal());
    System.out.println("当前页数据: ");
    userVOPage.getRecords().forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# 8. 多表关联查询

使用自定义SQL实现多表查询

MyBatis-Plus主要针对单表操作,复杂的多表查询一般通过自定义SQL实现:

/**
 * 用户Mapper接口
 */
public interface UserMapper extends BaseMapper<User> {
    /**
     * 关联查询用户及其部门信息
     * @param userId 用户ID
     * @return 用户信息(包含部门信息)
     */
    @Select("SELECT u.*, d.name as dept_name, d.code as dept_code " +
            "FROM user u " +
            "LEFT JOIN department d ON u.dept_id = d.id " +
            "WHERE u.id = #{userId}")
    UserDeptVO getUserWithDept(@Param("userId") Long userId);
    
    /**
     * 查询指定部门的所有用户
     * @param deptId 部门ID
     * @return 用户列表
     */
    List<User> getUsersByDeptId(@Param("deptId") Long deptId);
}

/* XML配置
<select id="getUsersByDeptId" resultType="com.example.entity.User">
    SELECT 
        u.*
    FROM 
        user u
    INNER JOIN 
        user_dept ud ON u.id = ud.user_id
    WHERE 
        ud.dept_id = #{deptId}
    ORDER BY 
        u.id
</select>
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 9. 常见查询场景示例

# 9.1 组合查询条件

/**
 * 复杂组合查询条件示例
 */
@Test
public void testComplexQuery() {
    // 创建查询条件
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    
    // 构建复杂查询条件:
    // (status = 'active' OR status = 'pending')
    // AND (age > 18 AND gender = '男')
    // AND (create_time BETWEEN '2023-01-01' AND '2023-12-31')
    queryWrapper
        // 第一组条件(OR关系)
        .and(wrapper -> wrapper
            .eq(User::getStatus, "active")
            .or()
            .eq(User::getStatus, "pending")
        )
        // 第二组条件(AND关系)
        .and(wrapper -> wrapper
            .gt(User::getAge, 18)
            .eq(User::getGender, "男")
        )
        // 第三组条件
        .between(User::getCreateTime, 
            DateUtil.parseDate("2023-01-01"), 
            DateUtil.parseDate("2023-12-31")
        )
        // 排序
        .orderByDesc(User::getCreateTime);
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 9.2 模糊查询与精确查询结合

/**
 * 模糊查询与精确查询结合示例
 */
@Test
public void testMixedQuery() {
    // 模拟搜索参数
    String keyword = "技术";  // 关键字
    String department = "研发部";  // 部门
    
    // 创建查询条件
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    
    // 构建查询条件:
    // 姓名或职位中包含关键字
    // AND 部门等于指定部门
    queryWrapper
        .and(wrapper -> wrapper
            .like(User::getName, keyword)
            .or()
            .like(User::getPosition, keyword)
        )
        .eq(User::getDepartment, department)
        .orderByDesc(User::getCreateTime);
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 9.3 区间查询

/**
 * 区间查询示例
 */
@Test
public void testRangeQuery() {
    // 模拟查询参数
    Integer minAge = 20;
    Integer maxAge = 30;
    Date startDate = DateUtil.parseDate("2023-01-01");
    Date endDate = DateUtil.parseDate("2023-06-30");
    
    // 创建查询条件
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    
    // 构建查询条件:
    // 年龄在指定范围内
    // 创建时间在指定日期范围内
    queryWrapper
        .between(User::getAge, minAge, maxAge)
        .between(User::getCreateTime, startDate, endDate)
        .orderByAsc(User::getAge);
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 10. 查询结果的映射规则

MyBatis-Plus对于结果映射有两种基本情况:

# 1. 基础映射规则:只能映射到泛型指定的实体类

使用BaseMapper内置方法(如selectById、selectList等)时,只能映射为Mapper接口中指定的泛型类型T:

// UserMapper接口定义
public interface UserMapper extends BaseMapper<User> {
    // 所有内置方法返回的都是User或User集合
}

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    
    public void example() {
        // 返回User对象
        User user = userMapper.selectById(1L);
        
        // 返回User列表
        List<User> users = userMapper.selectList(null);
        
        // 错误:无法直接返回UserVO
        // UserVO userVO = userMapper.selectById(1L); // 编译错误或运行时异常
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 2. 要使用VO/DTO等其他类型接收结果,必须自定义方法

正确的做法有以下几种:

方法1:自定义SQL方法(最常用)

public interface UserMapper extends BaseMapper<User> {
    // 必须自定义SQL来返回非User类型
    @Select("SELECT id, name as userName, age, email FROM user WHERE id = #{id}")
    UserVO getUserVOById(@Param("id") Long id);
    
    // 返回VO列表
    @Select("SELECT id, name as userName, age, dept_name as deptName FROM user u " +
            "LEFT JOIN department d ON u.dept_id = d.id")
    List<UserVO> listUserVOs();
}
1
2
3
4
5
6
7
8
9
10

方法2:手动转换对象(代码中处理)

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    
    // 在Service层手动转换
    public UserVO getUserVOById(Long id) {
        // 先查询实体
        User user = userMapper.selectById(id);
        if (user == null) {
            return null;
        }
        
        // 手动转换为VO
        UserVO vo = new UserVO();
        vo.setId(user.getId());
        vo.setUserName(user.getName());
        vo.setAge(user.getAge());
        // 设置其他字段...
        
        return vo;
    }
    
    // 使用工具类或框架批量转换
    public List<UserVO> listUserVOs() {
        List<User> users = userMapper.selectList(null);
        // 可以使用BeanUtils、MapStruct或ModelMapper等工具
        return users.stream()
            .map(user -> {
                UserVO vo = new UserVO();
                BeanUtils.copyProperties(user, vo);
                return vo;
            })
            .collect(Collectors.toList());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

方法3:使用继承关系(不推荐)

// VO继承实体类(不推荐,会造成紧耦合)
public class UserVO extends User {
    private String deptName;  // 额外字段
    // getter/setter...
}

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    
    // 利用继承关系,可能会有类型安全问题
    @SuppressWarnings("unchecked")
    public List<UserVO> getUserVOsUnsafe() {
        // 这种方式不类型安全,不推荐
        return (List<UserVO>)(List<?>)userMapper.selectList(null);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

总结

  1. MyBatis-Plus的BaseMapper内置方法只能映射为泛型指定的实体类
  2. 如果需要使用VO/DTO/其他自定义类型接收,必须创建自定义方法
  3. 有三种方式处理自定义类型返回:
    • 自定义SQL方法(最推荐)
    • 手动对象转换(适合逻辑复杂情况)
    • 继承关系转换(不推荐)

实际开发中,当需要自定义返回类型时,最常用和推荐的方式是编写自定义SQL方法,这样既保证类型安全,又可以优化查询性能。

# 11. 查询条件构建最佳实践

# 11.1 使用条件构造器的推荐方式

/**
 * 条件构造器使用的最佳实践
 */
public List<User> getUserList(UserQuery query) {
    // 1. 使用LambdaQueryWrapper,避免字段名硬编码
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    
    // 2. 使用condition条件参数,优雅处理动态条件
    queryWrapper
        .like(StringUtils.isNotBlank(query.getName()), User::getName, query.getName())
        .ge(query.getMinAge() != null, User::getAge, query.getMinAge())
        .le(query.getMaxAge() != null, User::getAge, query.getMaxAge())
        .eq(StringUtils.isNotBlank(query.getStatus()), User::getStatus, query.getStatus());
    
    // 3. 默认添加一个排序条件,避免结果不稳定
    queryWrapper.orderByDesc(User::getCreateTime);
    
    // 4. 对于大表,只查询需要的字段,减少数据传输量
    queryWrapper.select(User::getId, User::getName, User::getAge);

    // 5. 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);

    return userList;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 11.2 条件构造器性能优化

/**
 * 查询条件性能优化最佳实践
 */
public List<User> getOptimizedUserList(UserQuery query) {
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    
    // 1. 添加索引字段条件优先
    // 优先使用索引字段作为查询条件,提高查询效率
    queryWrapper.eq(StringUtils.isNotBlank(query.getStatus()), User::getStatus, query.getStatus());
    
    // 2. 避免使用左模糊查询,会导致索引失效
    // 不推荐:queryWrapper.likeLeft(User::getName, "张")
    // 推荐:使用右模糊或全模糊
    queryWrapper.likeRight(StringUtils.isNotBlank(query.getName()), User::getName, query.getName());
    
    // 3. 使用带索引的范围查询
    queryWrapper.ge(query.getMinAge() != null, User::getAge, query.getMinAge());
    
    // 4. 只查询必要的字段,避免大字段传输
    queryWrapper.select(User::getId, User::getName, User::getAge);
    
    // 5. 对于大数据量查询,使用分页
    if (query.needPagination()) {
        Page<User> page = new Page<>(query.getPageNum(), query.getPageSize());
        return userMapper.selectPage(page, queryWrapper).getRecords();
    }
    
    // 对于一般查询,限制最大返回数量
    queryWrapper.last("LIMIT 1000");
    
    return userMapper.selectList(queryWrapper);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 11.3 集中管理查询条件

对于复杂系统,推荐将查询条件逻辑集中到专门的条件构造器类中:

/**
 * 用户查询条件构造器
 * 集中管理用户相关的查询条件构建逻辑
 */
public class UserQueryBuilder {
    /**
     * 构建基础查询条件
     */
    public static LambdaQueryWrapper<User> buildBaseQuery(UserQuery query) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        
        // 添加基础查询条件
        queryWrapper
            .like(StringUtils.isNotBlank(query.getName()), User::getName, query.getName())
            .ge(query.getMinAge() != null, User::getAge, query.getMinAge())
            .le(query.getMaxAge() != null, User::getAge, query.getMaxAge())
            .eq(StringUtils.isNotBlank(query.getStatus()), User::getStatus, query.getStatus());
        
        return queryWrapper;
    }
    
    /**
     * 构建活跃用户查询条件
     */
    public static LambdaQueryWrapper<User> buildActiveUserQuery(Date sinceDate) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        
        queryWrapper
            .eq(User::getStatus, "active")
            .ge(sinceDate != null, User::getLastLoginTime, sinceDate)
            .orderByDesc(User::getLastLoginTime);
        
        return queryWrapper;
    }
    
    /**
     * 构建新注册用户查询条件
     */
    public static LambdaQueryWrapper<User> buildNewUserQuery(Integer days) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        
        // 计算N天前的日期
        Date startDate = DateUtils.addDays(new Date(), -days);
        
        queryWrapper
            .ge(User::getCreateTime, startDate)
            .orderByDesc(User::getCreateTime);
        
        return queryWrapper;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 12. 常见查询问题与解决方案

# 12.1 处理大数据量查询

当需要查询大量数据时,应避免一次性加载所有数据,可以采用以下方法:

/**
 * 大数据量分页查询示例
 * 避免一次性加载过多数据
 */
@Test
public void testLargeDataQuery() {
    // 查询条件
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.gt(User::getAge, 18);
    
    // 分页参数
    long pageSize = 100; // 每页数量
    long pageNum = 1;    // 起始页码
    boolean hasMore = true;
    
    // 分批次查询处理
    while (hasMore) {
        Page<User> page = new Page<>(pageNum, pageSize);
        page = userMapper.selectPage(page, queryWrapper);
        
        List<User> records = page.getRecords();
        if (records.isEmpty()) {
            hasMore = false;
        } else {
            // 处理当前页数据
            processUserData(records);
            
            // 判断是否还有更多数据
            hasMore = page.getCurrent() < page.getPages();
            pageNum++;
        }
    }
}

private void processUserData(List<User> users) {
    // 处理用户数据的逻辑
    System.out.println("处理用户数据:" + users.size() + "条");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 12.2 处理动态排序

有时候需要根据用户选择的字段进行排序:

/**
 * 动态排序示例
 * 根据用户选择的字段和顺序进行排序
 */
public List<User> getUsersWithDynamicSort(String sortField, boolean isAsc) {
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    
    // 设置查询条件
    queryWrapper.eq(User::getStatus, "active");
    
    // 动态排序
    switch (sortField) {
        case "age":
            queryWrapper.orderBy(true, isAsc, User::getAge);
            break;
        case "createTime":
            queryWrapper.orderBy(true, isAsc, User::getCreateTime);
            break;
        case "name":
            queryWrapper.orderBy(true, isAsc, User::getName);
            break;
        default:
            // 默认按创建时间降序
            queryWrapper.orderByDesc(User::getCreateTime);
    }
    
    return userMapper.selectList(queryWrapper);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 12.3 查询结果映射问题

有时候需要将查询结果映射到不同的对象:

/**
 * 查询结果映射示例
 * 将查询结果映射到DTO对象
 */
public List<UserDTO> getUserDTOs() {
    // 1. 先查询实体对象
    List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>()
        .eq(User::getStatus, "active"));
    
    // 2. 转换为DTO对象
    return users.stream()
        .map(user -> {
            UserDTO dto = new UserDTO();
            dto.setId(user.getId());
            dto.setName(user.getName());
            dto.setAge(user.getAge());
            dto.setStatus(user.getStatus());
            // 设置其他属性...
            return dto;
        })
        .collect(Collectors.toList());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 13. 高级查询技巧

# 13.1 使用嵌套查询

/**
 * 嵌套查询示例
 * 构建复杂的嵌套条件
 */
@Test
public void testNestedQuery() {
    // 创建查询条件
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    
    // 构建复杂条件:
    // (age < 30 AND (gender = '男' OR status = 'active'))
    // OR (age >= 30 AND gender = '女')
    queryWrapper
        .and(wrapper -> wrapper
            .lt(User::getAge, 30)
            .and(innerWrapper -> innerWrapper
                .eq(User::getGender, "男")
                .or()
                .eq(User::getStatus, "active")
            )
        )
        .or(wrapper -> wrapper
            .ge(User::getAge, 30)
            .eq(User::getGender, "女")
        );
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 13.2 使用SQL函数和表达式

/**
 * SQL函数和表达式示例
 * 在查询条件中使用数据库函数
 */
@Test
public void testSqlFunctions() {
    // 创建QueryWrapper对象
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
    // 1. 使用日期函数
    queryWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", "2023-08");
    
    // 2. 使用字符串函数
    queryWrapper.apply("LOWER(name) = {0}", "john");
    
    // 3. 使用数学计算
    queryWrapper.apply("age * 2 > {0}", 50);
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 13.3 使用EXISTS和NOT EXISTS

/**
 * EXISTS和NOT EXISTS示例
 * 使用子查询检查关联数据存在性
 */
@Test
public void testExistsQuery() {
    // 创建QueryWrapper对象
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
    // 使用EXISTS:查询有订单的用户
    queryWrapper.exists("SELECT 1 FROM order o WHERE o.user_id = user.id");
    
    // 使用NOT EXISTS:查询没有订单的用户
    // queryWrapper.notExists("SELECT 1 FROM order o WHERE o.user_id = user.id");
    
    // 执行查询
    List<User> userList = userMapper.selectList(queryWrapper);
    
    // 输出查询结果
    System.out.println("查询结果数量: " + userList.size());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
编辑此页 (opens new window)
上次更新: 2025/03/16, 20:49:53
MyBatis-Plus条件构造器
MyBatis-Plus常用插件

← MyBatis-Plus条件构造器 MyBatis-Plus常用插件→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式