MyBatis-Plus的基本使用
本文最后更新于:2023年11月9日 晚上
MyBatis-Plus的基本使用
使用MyBatis-Plus能够带来的好处是什么呢?MyBatis-Plus和MyBatis是一个怎样的关系?
| 1 |  | 
以上描述完全是个人理解,为了小伙伴们更好的学习MyBati-Plus可参考官方文档:https://baomidou.com
继续往下将带大家从Mybati-Plus的入门到常用的核心功能
1.mybatis-Plus快速入门体验
开发环境:SpringBoot 2.3.4+Mybatis-Plus 3.4.1+MySQL 8.0
注:不同的MyBatis-Plus版本可能在某些功能的配置上有所不同
- 创建数据库表并插入测试数据
| 1 |  | 
- 新建一个SpringBoot项目并在pom.xml文件中导入所需的Maven依赖
| 1 |  | 
- 在application.yaml文件中配置数据源 - 1 
 2
 3
 4
 5
 6- spring:
 datasource:
 driver-class-name: com.mysql.cj.jdbc.Driver
 url: jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=Asia/Shanghai
 username: root
 password: libo
- 创建User实体类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19- @Data
 /*全部参数的构造方法*/
 @AllArgsConstructor
 /*无参构造*/
 @NoArgsConstructor
 /*指定数据库表名*/
 @TableName(value = "user")
 /*实体类*/
 public class User {
 private Long id;
 private String name;
 private Integer age;
 private String email;
 }
- 创建userMapper接口并继承BaseMapper接口 
 别忘了在启动类上加入@MapperScan(value = “com.mybatiPlus.mapper”) //扫描mapper文件- 1 
 2
 3
 4
 5
 6- @Repository
 /*Mapper接口*/
 public interface userMapper extends BaseMapper<User> {
 }
- 使用MyBatis-Plus操作数据(这里就测试下查询user表的所有数据) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16- @SpringBootTest
 /*测试类*/
 public class mybatisPlusTest {
 /*注入持久层userMapper接口*/
 @Autowired
 private userMapper userMapper;
 /*查询user表中所有数据*/
 @Test
 public void seleteByList() {
 /*Wrapper是一个条件构造器,这里暂且先不适用*/
 List<User> userList = userMapper.selectList(null);
 /*打印List*/
 userList.forEach(System.out::println);
 }- 控制台打印的结果: 
 的确是把user表中的所有数据查询出来了,然而我们并没有编写SQL语句对吧,这就是MyBatis-Plus的强大之处。 
这里就有两个问题:1.userMapper下的方法哪里来的?2.SQL是谁写的?
方法来自BaseMapper,因为我们继承了他并且传入了泛型。SQL语句当然是MyBatis-Plus中封装的啦,这只是MyBatis-Plus强大功能中的其中之一
2.配置日志输出
- 在application.yaml中加入1 
 2
 3mybatis-plus:
 configuration:
 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- 再次测试查询所有方法,然后观察控制台与之前多了哪些东西? 
3.主键生成策略
什么是主键生成策略呢?在数据库中一张表的主键一般就是我们的id字段,但是主键字段的值就有很多种了。
比如常见的id自增,或者说是insert into插入数据的时候手动填入,那在MyBatis-Plus中又给我们带来哪些不同的生成策略呢?
- 插入一条数据到user表1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13/*添加数据*/
 @Test
 public void insert() {
 User user = new User();
 /*名字*/
 user.setName("周杰伦");
 /*年龄*/
 user.setAge(18);
 /*email*/
 user.setEmail("abc@163.com");
 /*添加数据*/
 userMapper.insert(user);
 }
- 查看日志输出,看MyBabtis-Plus默认给我们生成的id是什么? 
- 查看数据库
  
问题:为什么会生成这么长一串id呢?或者说这个id是根据什么生成的呢?下面就介绍MyBatis的主键生成策略
MyBatis-Plus中不同的主键生成策略:
| 1 |  | 
注:IdType是一个枚举类
所以我们刚刚插入的数据生成的id就是使用MyBatis-Plus默认的生成策略IdType.ID_WORKER,其中采用了雪花算法。
主键生成策略的详细介绍可参考:分布式系统主键id生成策略
如果想要使用不同的策略需要在实体类的主键字段上加上注解 @TableId(type = IdType.ASSIGN_UUID)
比如我们再测试一个自动生成的UUID,因为UUID包含字母那就要把主键id字段改为String类型,数据库主键字段类型为varchar
| 1 |  | 

    再次执行我们之前的添加数据方法,查看结果

记得将实体类主键类型和数据库表主键字段类型改回来,上面只做一个测试。
4.单表删除操作
| 1 |  | 

另外再补充两个不同的删除方式:
根据id批量删除
| 1 |  | 
根据Map条件删除
| 1 |  | 
5.单表逻辑删除
我们之前删除数据是直接从数据库表中删除的,删除之后表里面这条数据就没有了,对吧
那么逻辑删除就是:要删除的数据并不是真正的从表中删除,只是在查询时不展示这条数据即可。
例如就相当于回收站:被删除的数据在回收站,但是回收站并没有清空,我们只是判断它没有作用了,放到一边而已
如何实现:
- 数据库表新增一个字段并且给一个默认值
 假设我们设置逻辑删除字段的值默认为0 
- 实体类增加逻辑删除字段配上注解
 加上注解:@TableLogic1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22@Data
 /*全部参数的构造方法*/
 @AllArgsConstructor
 /*无参构造*/
 @NoArgsConstructor
 /*指定数据库表名*/
 @TableName(value = "user")
 public class User {
 @TableId(type = IdType.ID_WORKER)
 private Long id;
 private String name;
 private Integer age;
 private String email;
 /*逻辑删除*/
 @TableLogic
 private Integer delete;
 }
- 在application.yaml文件中配置MyBatisPlus逻辑删除组件1 
 2
 3
 4
 5
 6
 7mybatis-plus:
 #逻辑删除
 global-config:
 db-config:
 logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
 logic-delete-value: 1 # 逻辑已删除值(默认为 1)
 logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
- 配置完成之后让我们来测试一个删除方法1 
 2
 3
 4
 5
 6/*根据id删除数据*/
 @Test
 public void delete() {
 /*根据id删除*/
 userMapper.deleteById(3L);
 } 
 逻辑删除其实走的是update方法,把逻辑删除字段的值给修改了,我们设置的是未删除时字段默认为0,逻辑删除后字段为1
 然后在查询时加上条件deleted = 0,所以在查询时deleted字段为1的值我们并没有查询出来,只查询了值为0的数据 
6.单表更新操作
现在想把id为1的数据中name改为刘德华,看看应该如何操作?
| 1 |  | 
查看日志执行的SQL:
查看数据库表:
上面只是修改了一个name字段,如果修改多个字段呢?
| 1 |  | 
注意看执行的SQL语句,和上面修改一个字段相比较,相当于在修改数据时MyBatis-Plus会做一个实体类字段的的非空验证
实体类中不为空的字段就视为要修改的属性。
7.单表查询操作
| 1 |  | 
8.分页查询
一般分页的几种方式:
- 自己创建分页类,然后limit查询进行分页
- PageHelper插件分页
MyBatis-Plus这么强大当然也提供了分页插件,那我们就看看在MyBatis-Plus中如何使用分页?
首先在SpringBoot中创建一个配置类,然后添加方法注册一个Bean对象。这个配置类还会配置其他关于MyBatis-Plus的插件
| 1 |  | 
在测试类中新建一个方法进行对分页的测试:
注:Page 对象中有很多方法,比如:数据总数,总页数等等。
| 1 |  | 
9.自动填充功能
在开发中一张表起码有这样的两个字段吧,一个是数据的插入时间,还有一个就是数据的修改时间。
所谓自动填充就是数据在插入、修改的时候给具体的字段设置值。例如设置当前时间
其实这种实现有两种方式:
注:不管采用什么样的方式实现都必须有这两个字段
- 数据库级别(不推荐使用)
 数据的创建时间字段默认一栏写入CURRENT_TIMESTAMP,该字段就会在新增数据时自动填入当前时间(创建数据时填入该字段)
只需要勾选根据当前时间戳更新,该数据在修改时,updateTime字段就会自动填入当前时间(修改数据时更新该字段)

- 代码级别
如果使用第一种方法,我们在开发中不一定能有权限去修改数据库,非专业数据库工程师去操作也不太好
MyBatis-Plus给我们提供了代码级别的填充。
- 可以先看下这个枚举类:
| 1 |  | 
- 在实体类种创建两个字段: - 1 
 2
 3
 4
 5
 6
 7- /*创建时间*/
 @TableField(fill = FieldFill.INSERT)
 private Date cteateTime;
 /*修改时间*/
 @TableField(fill = FieldFill.INSERT_UPDATE)
 private Date updateTime;
- 创建一个类来继承 MetaObjectHandler,该类作为MyBatis-Plus的自动填充处理类: 
| 1 |  | 
- 至此在数据的插入时cteateTime和updateTime两个字段都会被填充,在数据修改时updateTime字段会被填充。 
10.乐观锁
乐观锁的实现方式:这里需要多增加一个字段,这里取名为version(版本)
- 先查询出当前数据的version字段
- 修改时带上这个version字段
- 执行修改的SQL语句时:set version = 新version where version = 旧version
- 如果第一次取出的version和修改时的version不同,那么就修改失败。修改成功那么就在旧version的值上+1
其实这里就是线程并发的问题:
那我们假设现在有AB两个线程,两个线程都要去执行修改同一条数据的操作,并且该数据的version字段为0,A线程执行时去查询值为0,B线程执行时查询值也为0。但是A线程先执行,那么version字段+1,那么现在version已经为1了,线程B去执行修改时发现 两次的version不一样,查询时为0,执行时为1,那么B线程就修改失败
看看MyBatis-Plus如何实现乐观锁:
数据库表和实体类都要新增一个version字段,并且在实体类字段上加上@Version注解,数据库字段给一个默认值
| 1 |  | 

在SpringBoot的代码中注入一个Bean对象
| 1 |  | 
11.wrapper 条件构造器
上面的SQL案例都是些比较简单的数据库操作,但是如何有很复杂的条件查询应该在MyBatis-Plus中如何使用?
这里就需要用到wrapper条件构造器,下面给大家举几个复杂条件的例子,wrapper 的功能远不止这些,参考官方文档进行编写
| 1 |  |