MyBatisPlus使用

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" # Mapper.xml文件地址,当前这个是默认值。
configuration:
map-underscore-to-camel-case: true # 开启下划线到驼峰命名转换
cache-enabled: false # 关闭二级缓存
global-config:
db-config:
id-type: auto # 全局id类型为自增长
update-strategy: not_null # 全局更新填充字段策略,只更新非null字段

2. 核心功能

2.1 条件构造器

除了新增以外,修改、删除、查询的 SQL 语句都需要指定 where 条件。因此 BaseMapper 中提供的相关方法除了以 id 作为 where 条件以外,还支持更加复杂的 where 条件。

2.1.1.QueryWrapper

image.png
查询:查询出名字中带 o 的,存款大于等于 1000 元的人。代码如下:

1
2
3
4
5
6
7
8
9
10
11
@Test
void testQueryWrapper() {
// 1.构建查询条件 where name like "%o%" AND balance >= 1000
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.select("id", "username", "info", "balance")
.like("username", "o")
.ge("balance", 1000);
// 2.查询数据
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() {
// 1.构建查询条件 where name = "Jack"
QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "Jack");
// 2.更新数据,user中非null字段都会作为set语句
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);
// 1.生成SQL
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
.setSql("balance = balance - 200") // SET balance = balance - 200
.in("id", ids); // WHERE id in (1, 2, 4)
// 2.更新,注意第一个参数可以给null,也就是不填更新字段和数据,
// 而是基于UpdateWrapper中的setSQL来更新
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() {
// 1.构建条件 WHERE username LIKE "%o%" AND balance >= 1000
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lambda()
.select(User::getId, User::getUsername, User::getInfo, User::getBalance)
.like(User::getUsername, "o")
.ge(User::getBalance, 1000);
// 2.查询
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() {
// 1.准备自定义查询条件
List<Long> ids = List.of(1L, 2L, 4L);
QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);

// 2.调用mapper的自定义方法,直接传递Wrapper
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,性能最好


MyBatisPlus使用
https://kongshuilinhua.github.io/2025/02/23/MyBatisPlus使用/
作者
FireFLy
发布于
2025年2月23日
许可协议