文章目录
- [MyBatis 逆向工程核心利器:Example 类全场景实战指南](#MyBatis 逆向工程核心利器:Example 类全场景实战指南)
-
- [一、什么是 Example 类?](#一、什么是 Example 类?)
- 二、核心对象关系拆解
- 三、常见查询场景代码实战
-
- [1. 基础单条件与范围查询 (AND)](#1. 基础单条件与范围查询 (AND))
- [2. 模糊查询 (LIKE) 与 集合查询 (IN)](#2. 模糊查询 (LIKE) 与 集合查询 (IN))
- [3. 多条件 OR 查询(重点与易错点)](#3. 多条件 OR 查询(重点与易错点))
- [4. 排序与去重 (ORDER BY & DISTINCT)](#4. 排序与去重 (ORDER BY & DISTINCT))
- [5. 结合 PageHelper 实现物理分页](#5. 结合 PageHelper 实现物理分页)
- [四、动态更新:Selective 与 非 Selective 的区别](#四、动态更新:Selective 与 非 Selective 的区别)
- 五、开发避坑总结
MyBatis 的 Example 类由 MyBatis Generator (MBG) 自动生成,用于在不手写 XML 条件语句的情况下,以纯 Java 面向对象的方式构建动态 SQL(包括单/多条件查询、模糊查询、IN、OR、分页与排序等)。
MyBatis 逆向工程核心利器:Example 类全场景实战指南
一、什么是 Example 类?
在使用 MyBatis Generator 逆向生成持久层代码时,每个实体类都会对应生成一个 XxxExample 类。
它的核心思想是 通过面向对象 API 组装 SQL 的 WHERE 子句 。底层通过维护一个 Criteria 列表,自动拼接 SQL 中的 AND、OR、LIKE、IN 等条件,避免了手动在 XML 中编写大量繁琐的 <if test="..."> 标签。
二、核心对象关系拆解
在开始编码前,先理清 Example 内部的三个关键角色:
XxxExample:查询的主体入口。负责管理排序(orderByClause)、去重(distinct)以及多个Criteria之间的逻辑连接。Criteria:条件容器。单个Criteria内的所有条件默认用AND拼接。- **
createCriteria()vsor()**: example.createCriteria():创建主条件容器(默认第一个Criteria)。example.or():新建一个Criteria并将其与之前的条件用OR连接。
三、常见查询场景代码实战
假设逆向生成的表为用户表 user,对应实体为 User,Mapper 为 UserMapper,条件构造类为 UserExample。
1. 基础单条件与范围查询 (AND)
目标 SQL:
sql
SELECT * FROM user
WHERE status = 1
AND age >= 18
AND age <= 30;
Java 代码实现:
java
UserExample example = new UserExample();
UserExample.Criteria criteria = example.createCriteria();
// 链式调用拼接 AND 条件
criteria.andStatusEqualTo(1)
.andAgeGreaterThanOrEqualTo(18)
.andAgeLessThanOrEqualTo(30);
List<User> users = userMapper.selectByExample(example);
2. 模糊查询 (LIKE) 与 集合查询 (IN)
目标 SQL:
sql
SELECT * FROM user
WHERE username LIKE '%jack%'
AND role_id IN (1, 2, 3);
Java 代码实现:
java
UserExample example = new UserExample();
UserExample.Criteria criteria = example.createCriteria();
// LIKE 模糊查询需自行拼接通配符 %
criteria.andUsernameLike("%jack%")
.andRoleIdIn(Arrays.asList(1, 2, 3));
List<User> users = userMapper.selectByExample(example);
3. 多条件 OR 查询(重点与易错点)
目标 SQL:
sql
SELECT * FROM user
WHERE (dept_id = 10 AND status = 1)
OR (dept_id = 20 AND role_id = 2);
Java 代码实现:
java
UserExample example = new UserExample();
// 第一个 Criteria (dept_id = 10 AND status = 1)
UserExample.Criteria criteria1 = example.createCriteria();
criteria1.andDeptIdEqualTo(10)
.andStatusEqualTo(1);
// 调用 or() 生成第二个 Criteria,二者以 OR 连接
UserExample.Criteria criteria2 = example.or();
criteria2.andDeptIdEqualTo(20)
.andRoleIdEqualTo(2);
List<User> users = userMapper.selectByExample(example);
4. 排序与去重 (ORDER BY & DISTINCT)
目标 SQL:
sql
SELECT DISTINCT * FROM user
WHERE status = 1
ORDER BY create_time DESC, id ASC;
Java 代码实现:
java
UserExample example = new UserExample();
example.createCriteria().andStatusEqualTo(1);
// 开启去重
example.setDistinct(true);
// 传入原生 SQL 排序片段(注意 SQL 注入风险,字段名需硬编码或校验)
example.setOrderByClause("create_time DESC, id ASC");
List<User> users = userMapper.selectByExample(example);
5. 结合 PageHelper 实现物理分页
Example 类本身不包含特定数据库的分页语法(如 MySQL 的 LIMIT)。生产环境中通常搭配 PageHelper 使用:
java
// 开启分页(第 1 页,每页 10 条)
PageHelper.startPage(1, 10);
UserExample example = new UserExample();
example.createCriteria().andStatusEqualTo(1);
example.setOrderByClause("id DESC");
// 紧随其后的 select 语句会被自动拦截并加上 LIMIT
List<User> list = userMapper.selectByExample(example);
PageInfo<User> pageInfo = new PageInfo<>(list);
四、动态更新:Selective 与 非 Selective 的区别
Example 还可配合 updateByExample 族函数完成批量/条件更新:
java
User updateUser = new User();
updateUser.setStatus(0); // 仅更新状态为停用
UserExample example = new UserExample();
example.createCriteria().andLastLoginTimeLessThan(oneYearAgoDate);
// 场景 A:推荐 - 只更新 entity 中非 NULL 的字段
userMapper.updateByExampleSelective(updateUser, example);
// 对应 SQL: UPDATE user SET status = 0 WHERE last_login_time < ?
// 场景 B:谨慎使用 - 会将 entity 中为 NULL 的属性一并覆盖到数据库
userMapper.updateByExample(updateUser, example);
// 对应 SQL: UPDATE user SET username = NULL, status = 0, ... WHERE last_login_time < ?
五、开发避坑总结
| 关注点 | 说明与排查建议 |
|---|---|
| 禁止复用对象 | 每次业务查询**必须 new 一个新的 Example**。旧对象内保留了历史 criteria 列表,复用会导致 SQL 条件无限追加。 |
or() 陷阱 |
example.or() 创建的是一个全新的 Criteria 分支。不要误以为在同一个 Criteria 实例内有 .orEqualTo() 这种方法。 |
| NULL 值安全 | andXxxEqualTo(val) 若传入 null 会直接抛出异常;若需匹配 IS NULL,必须调用专用的 andXxxIsNull() 方法。 |
| 复杂多表关联 | Example 只适合单表的 CRUD;涉及多表 JOIN、复杂子查询或聚合函数计算时,应回归 XML 手写 SQL 以保障可控性与执行性能。 |