MyBatisPlus系列第1篇简介

入门案例

MyBatisPlus是基于Mybatis框架基础上开发的增强型工具,旨在简化开发,提高效率。具有无侵入、强大的CRUD,支持Lambda、支持主键自动生成、内置分页插件等等实用的功能。

1.导入相关的数据库,创建一个名为mp_db的数据库,字符集选择utf8mb4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`password` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`age` int(3) NOT NULL,
`tel` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

INSERT INTO `user` VALUES (1, 'Tom', 'tom', 3, '188888888888');
INSERT INTO `user` VALUES (2, 'Jerry', 'jerry', 4, '166666666666');
INSERT INTO `user` VALUES (3, 'Jock', '123456', 41, '188313284343');
INSERT INTO `user` VALUES (4, '传智播客', 'itcast', 15, '503320302323');

SET FOREIGN_KEY_CHECKS = 1;

2.创建一个SpringBoot引导项目,只需要勾选Mysql的相关模块,创建完成后添加如下依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.eldpepar</groupId>
<artifactId>mp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mp</name>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!--数据库框架-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>


<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

3.创建与数据库相对于的bean类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.eldpepar.domain;

public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public String getTel() {
return tel;
}

public void setTel(String tel) {
this.tel = tel;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", age=" + age +
", tel='" + tel + '\'' +
'}';
}
}

4.编写dao层,这里不需要额外实现SQL语句,只需要继承BaseMapper,并且在泛型中填入bean类。最后加上@Mapper注解即可完成

1
2
3
4
5
6
7
8
9
10
package com.eldpepar.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.eldpepar.domain.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserDao extends BaseMapper<User> {

}

分页查询

1.设置分页拦截器作为Spring管理bean

1
2
3
4
5
6
7
8
9
10
@Configuration
public class MpConfig {

@Bean
public MybatisPlusInterceptor pageInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}

2.执行分页查询

1
2
3
4
5
6
7
8
9
10
```@Test
void testPageSelect() {
IPage page = new Page(2, 3);
userDao.selectPage(page, null);
System.out.println("当前页码:" + page.getCurrent());
System.out.println("每页总数据量:" + page.getSize());
System.out.println("总页数:" + page.getPages());
System.out.println("数据总量:" + page.getTotal());
System.out.println("当前页数据:" + page.getRecords());
}

如果需要查看查询日志,需要在yml文件中开启相关功能

1
2
3
4
# 控制台显示日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

条件查询

MybaitsPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合

1.格式一:常规格式(支持链式)

1
2
3
4
5
6
7
8
@Test
void selectWrapper() {
QueryWrapper<User> qw = new QueryWrapper<>();
//查询年龄大于18,小于65的
qw.le("age", 65).ge("age", 18);
List<User> users = userDao.selectList(qw);
System.out.println(users);
}

2.格式二:lambda格式(常规查询)

1
2
3
4
5
6
7
8
@Test
void selectLambdaWrapper() {
QueryWrapper<User> qw = new QueryWrapper<>();
//查询年龄大于18,小于65
qw.lambda().lt(User::getAge, 65).ge(User::getAge, 18);
List<User> users = userDao.selectList(qw);
System.out.println(users);
}

3.格式三:lambda格式(专属查询)

1
2
3
4
5
6
7
8
9
@Test
void selectLambdaLambdaWrapper() {
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//查询年龄小于于18,或大于30的
lqw.lt(User::getAge, 18).or().ge(User::getAge, 30);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}

null值处理

如果没有导入lombok相关的依赖先导入lombok依赖,在idea高版本继承了lombok插件,不需要额外安装lombok插件,如果是低版本还需要安装lombok插件

1
2
3
4
5
6
7
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>

设置一个类用来规定age的最大值

1
2
3
4
@Data
public class UserQuery extends User {
private Integer ageMax;
}

执行条件查询,如果其中一个条件不存在,则会绕过这个条件

1
2
3
4
5
6
7
8
9
10
11
@Test
void selectByNull() {
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper();
UserQuery userQuery = new UserQuery();
userQuery.setAge(10);
//userQuery.setAgeMax(30);
lqw.ge(null != userQuery.getAge(), User::getAge, userQuery.getAge());
lqw.lt(null != userQuery.getAgeMax(), User::getAge, userQuery.getAgeMax());
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}

查询投影

1.查询结果包含模型中部分属性

1
2
3
4
5
6
7
@Test
void selectByAtt() {
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.select(User::getId, User::getName, User::getAge);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}

2.查询结果包含模型中未定义的属性

1
2
3
4
5
6
7
8
@Test
void selectByNotAtt() {
QueryWrapper<User> qm = new QueryWrapper<>();
qm.select("count(*) as num,tel");
qm.groupBy("tel");
List<Map<String, Object>> maps = userDao.selectMaps(qm);
System.out.println(maps);
}

条件设置

通常在不同的需求中,需要设置不同的查询条件下面列出了一些常见的查询条件

1.用户登录(eq匹配)

1
2
3
4
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.eq(User::getName, userQuery.getName()).eq(User::getPassword, userQuery.getPassword());
User loginUser = userDao.selectOne(lqw);
System.out.println(loginUser);

2.购物设定价格区间、户籍设定年龄区间(le,ge匹配或between匹配)

1
2
3
4
5
6
7
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//方案一:设定上线下限
lqw.le(User::getAge,userQuery.getAge()).eq(User::getAge,userQuery.getAgeMax());
//方案二:设定范围
lqw.between(User::getAge,userQuery.getAge(),userQuery.getAgeMax());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);

3.查信息,搜索新闻(非全文检索:like匹配)

1
2
3
4
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.likeLeft(User::getTel, userQuery.getTel());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);

4.统计报表(分组查询聚合函数)

1
2
3
4
5
QueryWrapper<User> qw = new QueryWrapper<>();
qw.select("gender", "count(*) as nums");
qw.groupBy("gender");
List<Map<String, Object>> maps = userDao.selectMaps(qw);
System.out.println(maps);

映射匹配

如果表名或者是列名与数据库中的不同,就需要进行映射匹配,可以通过@TableName设置对应的表明,@TableField设置对应的列名以及其他的属性

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@TableName("tbl_user")
public class IUser {
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer online;
}

其中select值为false表示的是此列不查询,exist值为false表示该列在数据库中不存在

ID生成策略

可以通过@TableId注解来设置,type值用来设置ID生成策略,常见的Id生成策略有AUTO、雪花、UUID等。雪花算法是一个64位的二进制组成,包括一位占位符、41位时间戳、10位机器码、以及12位序列号组成
1.AUTO使用数据库id自增策略控制id生成
2.NONE不设置id生成策略
3.INPUT用户手工输入id
4.ASSIGN_ID雪花算法生成id(可兼容数值类型与字符串型)
5.ASSIGN_UUID以UUID生成算法作为id生成策略

1
2
3
4
public class User {
TableId(type = IdType.AUTO)
private Long id;
}

全局配置

可以全局配置表名的前缀后缀等,大大的简化开发过程

1
2
3
4
mybatis-plus:
global-config:
db-config:
table-prefix: tbl_

多记录操作

1.按主键删除多条记录

1
2
List<Long> ids = Arrays.asList(new Long[]{2,3});
userDao.deleteBatchIds(ids);

2.按主键查询多条记录

1
2
List<Long> ids = Arrays.asList(new Long[]{2,3});
List<User> userList = userDao.selectBatchIds(ids);

逻辑删除

为数据设置是否可用状态字段,删除时设置对待他字段为不可用状态,数据保留在数据库中

1.首先在数据库中添加一个长度为一的字段delted,并且设置默认值为0表示没有表删除
2.在bean类中添加@TableLogic表示该字段是逻辑删除字段,并且设置value值和delval值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Data
@TableName("tbl_user")
public class IUser {
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer online;
//逻辑删除字段
@TableLogic(value = "0",delval = "1")
private Integer delted;
}

测试类

1
2
3
4
5
@Test
void testDelAndSelect() {
iUserDao.deleteById(1L);
System.out.println(iUserDao.selectList(null));
}

乐观锁

修改过程中会产生并发访问问题,可以使用乐观锁,可以解决较小的并发问题。乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

1.在数据库表中添加锁标记字段version
2.实体类中添加对应字段,并设置当前字段为乐观锁

1
2
3
4
5
public class User {
private Long id;
@Version
private Integer version;
}

3.配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装

1
2
3
4
5
6
7
8
9
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mpInterceptor() {
MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mpInterceptor;
}
}

4.使用乐观锁机制在修改之前必须先获取到对应数据的version才可以正常进行

1
2
3
4
5
6
7
8
@Test
void testUpdate() {
//先查询数据,获取到version数据
User user = userDao.selectById(1L);
//执行数据修改操作
user.setName("Tom,....");
userDao.updateById(user);
}

MyBatisPlus系列第1篇简介
https://www.eldpepar.com/coding/54847/
作者
EldPepar
发布于
2023年2月28日
许可协议