1. 使用步骤
1.1 引入 MyBatisPlus 依赖
MyBatisPlus 官方提供了 starter,其中集成了 Mybatis 和 MybatisPlus 的所有功能,并且实现了自动装配效果。
因此我们可以用 MybatisPlus 的 starter 代替 Mybatis 的 starter:
1 2 3 4 5
| <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> <>dependency>
|
1.2 定义 Mapper
1 2
| public interface UserMapper extends BaseMapper<User> { }
|
1.3 常用注解
MyBatisPlus 通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
- 类名驼峰转下划线作为表名
- 名为 id 的字段作为主键
- 变量名驼峰转下划线作为字段名
MybatisPlus 中比较常用的几个注解如下:
- @TableName:用来指定表名
- @TableId:用来指定表中的主键字段信息
- @TableField:用来指定表中的普通字段信息
其中 TableId 支持两个属性:value(指定主键名)和 type(指定主键生成策略)。
IdType 枚举:
- AUTO:数据库自增长(如果想要主键自增需要指定为 AUTO,否则默认的方法是第三种雪花算法)
- INPUT:通过 set 方法自行输入
- ASSIGN_ID:分配 ID,接口 IdentifierGenerator 的方法 nextId 来生成 id,默认实现类为 DefaultIdentifierGenerator 雪花算法
使用@TableField 的常见场景:
- 成员变量名与数据库字段名不一致
- 成员变量名以 is 开头,且是布尔值(反射的时候会把 is 去掉,所以需要指定)
- 成员变量名与数据库关键字冲突(例如 order 需要转义为`order`)
- 成员变量不是数据库字段(指定 exist=false)
1.4 常见配置
1 2 3 4 5 6 7 8 9 10
| mybatis-plus: type-aliases-package: com.itheima.mp.domain.po mapper-locations: "classpath*:/mapper/**/*.xml" configuration: map-underscore-to-camel-case: true cache-enabled: false global-config: db-config: id-type: auto update-strategy: not_null
|
2. 核心功能
2.1 条件构造器
除了新增以外,修改、删除、查询的 SQL 语句都需要指定 where 条件。因此 BaseMapper 中提供的相关方法除了以 id 作为 where 条件以外,还支持更加复杂的 where 条件。
2.1.1.QueryWrapper

查询:查询出名字中带 o 的,存款大于等于 1000 元的人。代码如下:
1 2 3 4 5 6 7 8 9 10 11
| @Test void testQueryWrapper() { QueryWrapper<User> wrapper = new QueryWrapper<User>() .select("id", "username", "info", "balance") .like("username", "o") .ge("balance", 1000); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
|
更新:更新用户名为 jack 的用户的余额为 2000,代码如下:
1 2 3 4 5 6 7 8 9
| @Test void testUpdateByQueryWrapper() { QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "Jack"); User user = new User(); user.setBalance(2000); userMapper.update(user, wrapper); }
|
2.1.2.UpdateWrapper
基于 BaseMapper 中的 update 方法更新时只能直接赋值,对于一些复杂的需求就难以实现。
例如:更新 id 为 1,2,4 的用户的余额,扣 200
SET 的赋值结果是基于字段现有值的,这个时候就要利用 UpdateWrapper 中的 setSql 功能了:
1 2 3 4 5 6 7 8 9 10 11
| @Test void testUpdateWrapper() { List<Long> ids = List.of(1L, 2L, 4L); UpdateWrapper<User> wrapper = new UpdateWrapper<User>() .setSql("balance = balance - 200") .in("id", ids); userMapper.update(null, wrapper); }
|
2.1.3.LambdaQueryWrapper
无论是 QueryWrapper 还是 UpdateWrapper 在构造条件的时候都需要写死字段名称,不推荐。
那么如何获取字段名?
其中一种办法是基于变量的 gettter 方法结合反射技术。因此我们只要将条件对应的字段的 getter 方法传递给 MybatisPlus,它就能计算出对应的变量名了。而传递方法可以使用 JDK8 中的方法引用和 Lambda 表达式。
因此 MybatisPlus 又提供了一套基于 Lambda 的 Wrapper,包含两个:
- LambdaQueryWrapper
- LambdaUpdateWrapper
分别对应 QueryWrapper 和 UpdateWrapper
1 2 3 4 5 6 7 8 9 10 11 12
| @Test void testLambdaQueryWrapper() { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.lambda() .select(User::getId, User::getUsername, User::getInfo, User::getBalance) .like(User::getUsername, "o") .ge(User::getBalance, 1000); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
|
2.2.自定义 SQL
SQL 语句最好都维护在持久层,而不是业务层。就当前案例来说,由于条件是 in 语句,只能将 SQL 写在 Mapper.xml 文件,利用 foreach 来生成动态 SQL。
这实在是太麻烦了。假如查询条件更复杂,动态 SQL 的编写也会更加复杂。
所以,MybatisPlus 提供了自定义 SQL 功能,可以让我们利用 Wrapper 生成查询条件,再结合 Mapper.xml 编写 SQL
1 2 3 4 5 6 7 8 9
| @Test void testCustomWrapper() { List<Long> ids = List.of(1L, 2L, 4L); QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);
userMapper.deductBalanceByIds(200, wrapper); }
|
1 2 3 4 5 6 7 8 9 10 11 12
| package com.itheima.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.itheima.mp.domain.po.User; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Update; import org.apache.ibatis.annotations.Param;
public interface UserMapper extends BaseMapper<User> { @Select("UPDATE user SET balance = balance - #{money} ${ew.customSqlSegment}") void deductBalanceByIds(@Param("money") int money, @Param("ew") QueryWrapper<User> wrapper); }
|
2.3 Service 接口
MybatisPlus 不仅提供了 BaseMapper,还提供了通用的 Service 接口及默认实现,封装了一些常用的 service 模板方法。
通用接口为 IService,默认实现为 ServiceImpl,其中封装的方法可以分为以下几类:
- save:新增
- remove:删除
- update:更新
- get:查询单个结果
- list:查询集合结果
- count:计数
- page:分页查询
2.3.2.基本用法
由于 Service 中经常需要定义与业务有关的自定义方法,因此我们不能直接使用 IService,而是自定义 Service 接口,然后继承 IService 以拓展方法。同时,让自定义的 Service 实现类继承 ServiceImpl,这样就不用自己实现 IService 中的接口了。
首先,定义 IUserService,继承 IService:
1 2 3 4 5 6 7 8
| package com.itheima.mp.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.itheima.mp.domain.po.User;
public interface IUserService extends IService<User> { }
|
编写 UserServiceImpl 类,继承 ServiceImpl,实现 UserService:
1 2 3 4 5 6 7 8 9 10 11 12
| package com.itheima.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.itheima.mp.domain.po.User; import com.itheima.mp.domain.po.service.IUserService; import com.itheima.mp.mapper.UserMapper; import org.springframework.stereotype.Service;
@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService { }
|
2.3.3.IService 批量新增
需求:批量插入 10 万条用户数据,并作出对比:
普通 for 循环插入
IService 的批量插入
开启 rewriteBatchedStatements=true 参数
批处理方案:
普通 for 循环逐条插入速度极差,不推荐
MP 的批量新增,基于预编译的批处理,性能不错
配置 jdbc 参数,开 rewriteBatchedStatements,性能最好