MyBatis-Plus 核心功能
条件构造器、Wrapper、自定义 SQL、IService
一、条件构造器(Wrapper)
1. 为什么需要 Wrapper
BaseMapper 提供的 CRUD 方法主要针对主键(ID)操作,而实际开发中常见需求包括:
- 多条件查询
- 模糊查询
- 区间查询
- IN 查询
- 条件更新
- 条件删除
如果全部手写 MyBatis 动态 SQL,会增加开发成本。
Wrapper 就是 MyBatis-Plus 提供的条件构造器,用于动态拼接 SQL 的 WHERE 条件,大幅减少 XML 与动态 SQL 编写。
2. Wrapper 继承体系
Wrapper │AbstractWrapper ├── QueryWrapper ├── UpdateWrapper ├── LambdaQueryWrapper └── LambdaUpdateWrapper
(1)Wrapper
- 顶层抽象父类
- 定义统一规范
- 一般不会直接使用
(2)AbstractWrapper
所有 Wrapper 的核心父类。
封装了几乎所有 SQL 条件方法。
| 方法 | SQL |
|---|---|
| eq | = |
| ne | != |
| gt | > |
| ge | >= |
| lt | < |
| le | <= |
| like | LIKE ‘%value%’ |
| likeLeft | LIKE ‘%value’ |
| likeRight | LIKE ‘value%’ |
| notLike | NOT LIKE |
| between | BETWEEN … AND … |
| notBetween | NOT BETWEEN |
| in | IN (…) |
| notIn | NOT IN (…) |
| isNull | IS NULL |
| isNotNull | IS NOT NULL |
| orderByAsc | ORDER BY ASC |
| orderByDesc | ORDER BY DESC |
(3)QueryWrapper
用于:
- 条件查询
- 条件删除
- 固定值更新
特点:
支持指定查询字段。
javawrapper.select("id","user_name","balance");
避免:
sqlselect *
提高查询效率。
(4)UpdateWrapper
主要用于:
复杂更新。
例如:
sqlbalance = balance - 200
提供:
javasetSql()
可以执行数据库运算。
例如:
javawrapper.setSql("balance = balance - 200");
(5)Lambda 系列 Wrapper(推荐)
包括:
- LambdaQueryWrapper
- LambdaUpdateWrapper
普通 Wrapper:
javawrapper.eq("user_name","Tom");
Lambda Wrapper:
javawrapper.eq(User::getUserName,"Tom");
优点:
- 不使用字符串
- 字段重构不会失效
- 编译期检查
- 可读性更高
企业开发推荐优先使用 Lambda Wrapper。
3. 常用示例
(1)多条件查询
需求:
- 用户名包含 o
- 余额 ≥1000
- 返回指定字段
javaLambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.select( User::getId, User::getUserName, User::getInfo, User::getBalance) .like(User::getUserName,"o") .ge(User::getBalance,1000); List<User> list = userMapper.selectList(wrapper);
(2)条件更新
需求:
用户名为"杰克"修改余额。
javaUser user = new User();user.setBalance(2000); LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(User::getUserName,"杰克"); userMapper.update(user,wrapper);
(3)字段运算更新
需求:
1、2、4号用户统一扣除200元。
javaUpdateWrapper<User> wrapper = new UpdateWrapper<>(); wrapper.setSql("balance = balance - 200") .in("id",List.of(1L,2L,4L)); userMapper.update(null,wrapper);
4. Wrapper 使用建议
| 场景 | 推荐 |
|---|---|
| 查询 | LambdaQueryWrapper |
| 条件删除 | LambdaQueryWrapper |
| 固定值更新 | LambdaUpdateWrapper |
| 字段自增、自减 | UpdateWrapper(setSql) |
推荐原则:优先使用 Lambda Wrapper,仅在需要编写 SQL 运算时使用 UpdateWrapper。
二、自定义 SQL
1. 为什么需要自定义 SQL
虽然 MP 可以生成大量 CRUD SQL,但仍存在局限:
例如:
- 多表联查
- 聚合统计
- SQL 函数
- 字段计算
- 复杂 UPDATE
- 特殊业务 SQL
因此实际开发通常采用:
SQL 主体自己写,WHERE 条件交给 Wrapper。
这种方式既灵活,又能利用 MP 的动态条件能力。
2. 固定写法
Mapper 方法:
javavoid updateBalance( @Param(Constants.WRAPPER) Wrapper<User> wrapper, @Param("amount") Integer amount);
SQL:
java@Update("""update tb_userset balance = balance - #{amount}${ew.customSqlSegment}""")
其中:
${ew.customSqlSegment}
会自动拼接:
sqlwhere ...
无需自己写动态 SQL。
3. 示例
Mapper
java@Update("""update tb_userset balance = balance - #{amount}${ew.customSqlSegment}""")void updateBalance( @Param(Constants.WRAPPER) Wrapper<User> wrapper, @Param("amount") Integer amount);
Service
javaLambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.in(User::getId, List.of(1L,2L,4L)); userMapper.updateBalance(wrapper,200);
4. 适用场景
推荐用于:
- 多表查询
- 聚合统计
- SQL 函数
- 字段计算
- 特殊更新
- 企业统一管理 SQL
三、IService
1. IService 的作用
BaseMapper
负责:
DAO 层数据库操作。
IService
负责:
业务层通用 CRUD。
优点:
- 减少重复代码
- 封装批量操作
- 支持链式调用
- 更符合三层架构
2. 继承规范
Service 接口
javapublic interface IUserService extends IService<User> {}
Service 实现类
java@Servicepublic class UserServiceImpl extends ServiceImpl<UserMapper,User> implements IUserService {}
ServiceImpl
已经实现了:
IService 所有基础 CRUD。
并提供:
javabaseMapper
可直接访问 Mapper。
3. 常用方法
新增
| 方法 | 说明 |
|---|---|
| save | 单条新增 |
| saveBatch | 批量新增 |
| saveOrUpdate | 有ID更新,无ID新增 |
| saveOrUpdateBatch | 批量新增或更新 |
删除
| 方法 | 说明 |
|---|---|
| removeById | 根据ID删除 |
| removeByIds | 批量删除 |
| remove | 条件删除 |
更新
| 方法 | 说明 |
|---|---|
| updateById | 根据ID更新 |
| updateBatchById | 批量更新 |
| update(entity,wrapper) | 条件更新 |
查询
| 方法 | 说明 |
|---|---|
| getById | 查询单条 |
| getOne | 条件查询单条 |
| list | 查询列表 |
| listByIds | 批量查询 |
| count | 统计 |
| page | 分页查询 |
4. Lambda 链式查询(推荐)
javaList<User> list =this.lambdaQuery() .like(query.getName()!=null, User::getUserName, query.getName()) .eq(query.getStatus()!=null, User::getStatus, query.getStatus()) .ge(query.getMinBalance()!=null, User::getBalance, query.getMinBalance()) .le(query.getMaxBalance()!=null, User::getBalance, query.getMaxBalance()) .list();
特点:
- 自动判断条件
- 条件为空不拼接 SQL
- 可代替大量 XML
<if>标签
5. Lambda 更新
javathis.lambdaUpdate() .set(User::getBalance,remainBalance) .set(remainBalance==0, User::getStatus,2) .eq(User::getId,userId) .update();
注意:
最后必须调用:
java.update();
SQL 才会执行。
6. BaseMapper 与 IService 的使用建议
| 场景 | 推荐 |
|---|---|
| 简单 CRUD | IService |
| 存在业务逻辑 | 自定义 Service |
| 特殊 SQL | 自定义 Mapper |
推荐分层:
Controller │ ▼Service(业务逻辑) │ ▼Mapper(数据库访问)
四、批量插入性能优化
1. 三种批量插入方式
(1)循环 save(不推荐)
javafor(User user:list){ userService.save(user);}
特点:
- 每次执行一条 INSERT
- 网络开销大
- 性能最差
(2)saveBatch(推荐)
javauserService.saveBatch(list);
特点:
- JDBC 批处理
- 默认分批提交
- 推荐批次:1000 条
适用于绝大多数业务。
(3)MySQL 驱动批处理(最佳性能)
数据库连接增加:
propertiesrewriteBatchedStatements=true
示例:
propertiesspring.datasource.url=jdbc:mysql://localhost:3306/mp?rewriteBatchedStatements=true
作用:
MySQL 驱动会自动把多条 INSERT 合并成一条批量 SQL。
性能可提升数倍。
2. 批量开发建议
- 单批建议 500~1000 条
- 开启
rewriteBatchedStatements=true - 超大批量可使用 XML
foreach - 避免循环逐条插入
五、开发规范总结
Wrapper
- 查询推荐
LambdaQueryWrapper - 更新推荐
LambdaUpdateWrapper - 字段计算使用
UpdateWrapper#setSql()
自定义 SQL
适用于:
- 多表查询
- 聚合统计
- SQL 函数
- 字段计算
- 特殊更新
推荐:
SQL 主体写在 Mapper,动态条件交给 Wrapper。
IService
适用于:
- 通用 CRUD
- 批量操作
- 链式查询
- 链式更新
业务逻辑写在 Service,数据库操作写在 Mapper。
批量操作
推荐顺序:
循环 save ↓saveBatch ↓saveBatch + rewriteBatchedStatements(最佳)
六、本章重点速记
- Wrapper 用于动态拼接 SQL 条件。
- Lambda Wrapper 是企业开发首选,避免硬编码字段名。
- QueryWrapper 适合查询与普通更新,UpdateWrapper 适合字段计算。
- 自定义 SQL 采用"SQL 主体手写 + Wrapper 拼接 WHERE"模式。
- IService 封装了业务层通用 CRUD,减少重复代码。
- LambdaQuery/LambdaUpdate 支持动态条件,可替代大量 XML 动态 SQL。
- 批量插入优先使用
saveBatch(),并开启rewriteBatchedStatements=true提升性能。

