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
6spring:
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 |
|