【笔记】SpringBoot项目整合MyBatisPlus

前言

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。(官网

SpringBoot项目整合MyBatisPlus学习笔记

快速入门

添加依赖

  • mybatis-plus-boot-starter依赖中包含了mybatis-spring的依赖,所以不需要重复添加MyBatis的依赖。如果重复添加,并且版本不相同,会有问题
pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- SpringBoot相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<!-- MySQL JDBC相关依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<!-- MyBatisPlus相关依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>

添加配置

src/main/resources/application.yml
1
2
3
4
5
6
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///
username:
password:

创建实体类

src/main/java/com/pojo/User.java
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
package com.pojo;

public class User {

private int id;
private String name;

public int getId() {
return id;
}

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

public String getName() {
return name;
}

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

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

持久层

使用Mapper注解定义bean

src/main/java/com/dao/UserDao.java
1
2
3
4
5
6
7
8
9
package com.dao;

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

@Mapper
public interface UserDao extends BaseMapper<User> {
}

使用MapperScan方式扫描bean

  • 不使用Mapper注解,而是在主启动类添加@MapperScan注解,实现Mapper的扫描

com.dao:指定扫描的包

1
@MapperScan("com.dao")

直接使用MyBatisPlus封装好的CRUD方法

src/test/java/com/dao/UserDaoTests.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.dao;

import com.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class UserDaoTests {

@Autowired
private UserDao userDao;

@Test
public void test() {
System.out.println(userDao.selectList(null));
}
}

使用MyBatisPlus实现CRUD增删改查操作

创建条件对象

  • 所有需要传递条件的操作都需要先创建条件对象,然后将条件作为参数传入

QueryWrapper类型的条件

字符串传值
1
2
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("字段名", 值);
设置查询投影
  • 设置想要查询出来的结果包含哪些字段
1
queryWrapper.select("id", "name");
重载方法
  • 第一个参数为true时生效,第一个参数为false时无效
1
queryWrapper.eq(true, "字段名", 值);
Lambda表达式传值
1
2
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(User::getId, 值);

LambdaQueryWrapper类型

Lambda表达式传值
1
2
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getId, 值);
重载方法
  • 第一个参数为true时生效,第一个参数为false时无效
1
queryWrapper.eq(true, User::getId, 值);
设置查询投影
  • 设置想要查询出来的结果包含哪些字段
1
queryWrapper.select(User::getId, User::getName);

查询条件方法

  • 主要针对于查询操作的条件。需要先创建条件对象,再在条件对象中添加查询条件
  • 字段名传值时,既可以使用字符串方式,也可以使用Lambda表达式方式
    • 本案例使用字符串方式

范围匹配

区间
1
queryWrapper.between("字段名", 最小值, 最大值);
相等
1
queryWrapper.eq("字段名", 值);
大于
1
queryWrapper.gt("字段名", 值);
小于
1
queryWrapper.lt("字段名", 值);
大于等于
1
queryWrapper.ge("字段名", 值);
小于等于
1
queryWrapper.le("字段名", 值);
多条件范围
并且条件
1
2
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.ge(User::getId, 1).le(User::getId, 1);
或者条件
1
2
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.le(User::getId, 1).or().ge(User::getId, 1);

模糊匹配

从任意位置匹配
  • 相当于SQL语句中%关键字%
1
queryWrapper.like("字段名", "关键字");
从左侧匹配
  • 相当于SQL语句中关键字%
1
queryWrapper.likeLeft("字段名", "关键字");
从右侧匹配
  • 相当于SQL语句中%关键字
1
queryWrapper.likeRight("字段名", "关键字");

分组

  • 分组统计个数

<group>:指定分组的字段名

1
2
queryWrapper.select("COUNT(*), <group>");
queryWrapper.groupBy("<group>");

新增

  • 返回执行成功的行数
1
userDao.insert(new User());

删除

  • 返回执行成功的行数

根据id删除数据

<id>:需要删除的id

1
userDao.deleteById(<id>);

根据多个id删除数据

1
2
3
4
ArrayList<Integer> list = new ArrayList<>();
list.add(<id>);
list.add(<id>);
userMapper.deleteBatchIds(list);

根据条件对象删除数据

1
userMapper.delete(queryWrapper);

修改

根据id修改数据

<id>:id
<name_new>:修改后的字段值

1
2
3
4
User user = new User();
user.setId(<id>);
user.setName(<name_new>);
userDao.updateById(user);

查询

根据id查询数据

1
userDao.selectById();

根据多个id查询数据

1
2
3
4
ArrayList<Integer> list = new ArrayList<>();
list.add(<id>);
list.add(<id>);
userMapper.selectBatchIds(list);

根据条件查询数据

1
userDao.selectList(new User());

根据条件对象查询数据

1
userDao.selectList(queryWrapper);
  • 无条件查询所有数据
1
userDao.selectList(null);

根据条件对象查询数据并重新封装

  • 根据条件对象查询数据,将查询结果封装为List<Map<>>
1
List<Map<String, Object>> maps = userDao.selectMaps(queryWrapper);
1
List<Map<String, Object>> maps = userDao.selectMaps(null);

查询个数

根据条件对象查询个数

1
userMapper.selectCount(queryWrapper);
查询所有数据个数
  • 无条件查询数据的个数
1
userMapper.selectCount(null);

数据表与字段的映射关系配置

实体类添加注解

  • 默认实体类的类名要与数据表的表名首字母大写后相同
  • 默认实体类的属性名要与数据表的字段名相同

@TableName("数据表名"):指定数据表的配置,指定映射的数据表名
@TableId():指定主键的配置

type = IdType.AUTO:指定主键自增策略的配置

IdType.NONE:缺省值,无策略
IdType.INPUT:自己手动指定
IdType.AUTO:主键自增
IdType.ASSIGN_UUIDIdType.UUID:通过UUID生成
IdType.ASSIGN_IDIdType.ID_WORKEDIdType.ID_WORKED_STR:通过雪花算法生成

value = "字段名":指定在数据表中映射的字段名

@TableField():指定字段配置

value = "字段名":指定在数据表中映射的字段名
exist = false:指定此属性与数据表中的字段映射是否存在

true:缺省值,此属性与数据表中的字段映射存在
false:此属性与数据表中的字段映射不存在

select = false:指定此属性是否作为SQL查询语句的查询结果

true:缺省值,此属性作为SQL查询语句的查询结果
false:此属性不作为SQL查询语句的查询结果

src/main/java/pojo/User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@TableName("user")
public class User {

@TableId(type = IdType.AUTO, value = "id")
private Integer id;

@TableField(value = "name")
private String name;

@TableField(select = false)
private String password;

@TableField(exist = false)
private String type;
}

分页查询

创建拦截器配置类

  • 创建一个MyBatisPlus拦截器bean,在MyBatisPlus拦截器中添加MyBatisPlus分页拦截器
src/main/java/com/conf/MyBatisPlusConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.conf;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 添加分页拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}

创建分页对象

1
2
IPage iPage = new Page(指定页码, 指定当前页的数据);
userDao.selectPage(iPage, null);

iPage.getPages():获取一共多少页
iPage.getTotal():获取一共多少条数据
iPage.getCurrent():获取当前页码值
iPage.getSize():获取每页多少条数据
iPage.getRecords():当前页的所有数据

逻辑删除

  • 在数据表中指定一个字段deleted,用于逻辑删除
  • 如果SQL查询语句如果有逻辑删除字段,每个SQL语句末尾会追加WHERE deleted=0
  • 如果SQL删除语句如果有逻辑删除字段,那么删除操作改为修改逻辑删除字段的操作

实体类添加字段

@TableLogic():指定逻辑删除字段

value = "":指定没有被删除的逻辑值
delval = "":指定被删除的逻辑值

1
2
3
4
5
public class User {

@TableLogic(value = "0", delval = "1")
private Integer deleted;
}

乐观锁(修改操作并发处理)

  • 如果请求的并发量在2000以内,可以采用乐观锁的方式解决高并发
  • 在数据表中指定一个字段version,用于定义版本
  • 当执行修改SQL语句时如果有版本字段,那么除了修改业务字段,还会将版本字段自增1,表示版本修改,同时会在末尾追加WHERE version=版本号

创建拦截器配置类

src/main/java/com/conf/MyBatisPlusConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.conf;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 添加乐观锁拦截器
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}

实体类添加字段

@Version:指定乐观锁字段

src/main/java/pojo/User.java
1
2
3
4
5
public class User {

@Version
private Integer version;
}

在执行修改SQL语句时添加版本号

  1. 通过id,执行查询语句,得到旧的版本号
  2. 修改内容
  3. 执行修改时,将版本号和修改后的内容一并传递

<id>:id
<name_new>:修改后的名称
<version>:版本号

1
2
3
4
5
6
// 先根据id查询,包括版本号
User user = userDao.selectById(<id>);
// 设置修改的内容
user.setName(<name_new>);
// 执行修改
userDao.updateById(user);

其他配置

MyBatisPlus开启控制台的日志

src/main/resources/application.yml
1
2
3
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

清除MyBatisPlus Banner

1
2
3
mybatis-plus:
global-config:
banner: false

指定xml的mapper文件扫描路径

1
2
mybatis-plus:
mapper-locations: classpath:/mappers/*.xml

开启驼峰命名映射

  • 数据库的字段可能会采用_的方式连接多个单词作为字段名
  • Java中通常使用驼峰命名法为类的属性命名
  • 开启驼峰命名映射后,类的属性名与数据库的字段名映射关系,从原本的xxXx=>xxXx,改为xxX=>xxx_xx
1
2
3
mybatis-plus:
configuration:
map-underscore-to-camel-case: true

设置主键映射的默认的自增策略

none:缺省值,无策略
input:自己手动指定
auto:主键自增
assign_uuiduuid:通过UUID生成
assign_idid_workerid_worker_str通过雪花算法生成

1
2
3
4
mybatis-plus:
global-config:
db-config:
id-type: assign_uuid

设置表名映射时的表名前缀

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

设置逻辑删除字段的配置

指定逻辑删除字段的字段名

1
2
3
4
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted

指定没有被删除的逻辑值

1
2
3
4
mybatis-plus:
global-config:
db-config:
logic-not-delete-value: 0

指定被删除的逻辑值

1
2
3
4
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1

代码生成器

引入依赖

pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>

<!-- velocity模版引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>

创建生成器类

src/main/java/com/Generator.java
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
61
62
63
64
65
66
67
68
package com;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;

public class Generator {
public static void main(String[] args) {
/* 创建生成器对象 */
AutoGenerator autoGenerator = new AutoGenerator();

/* 设置数据库相关配置 */
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUrl("jdbc:mysql:///");
dataSourceConfig.setUsername("");
dataSourceConfig.setPassword("");
autoGenerator.setDataSource(dataSourceConfig);

/* 设置全局配置 */
GlobalConfig globalConfig = new GlobalConfig();
// 设置代码生成后的输出路径
globalConfig.setOutputDir("");
// 设置代码生成后是否自动打开输出路径
globalConfig.setOpen(false);
// 设置作者名
globalConfig.setAuthor("作者");
// 设置是否覆盖之前生成的文件
globalConfig.setFileOverride(true);
// 设置数据层接口名,%s表示模块名称占位符
globalConfig.setMapperName("%sDao");
// 设置Id生成策略
globalConfig.setIdType(IdType.ASSIGN_ID);
autoGenerator.setGlobalConfig(globalConfig);

/* 设置包名相关配置 */
PackageConfig packageConfig = new PackageConfig();
// 设置根级包名
packageConfig.setParent("com");
// 设置实体类包名
packageConfig.setEntity("pojo");
// 设置数据层包名
packageConfig.setMapper("dao");
autoGenerator.setPackageInfo(packageConfig);

/* 设置策略相关配置 */
StrategyConfig strategyConfig = new StrategyConfig();
// 设置当前参与生成的表名,如果不指定则包含所有数据表
//strategyConfig.setInclude("user");
// 设置数据表名称的前缀,在生成类名时会去除这个前缀
strategyConfig.setTablePrefix("t_");
// 设置是否启用Lombok
strategyConfig.setEntityLombokModel(true);
// 设置是否启用Rest风格
strategyConfig.setRestControllerStyle(true);
// 设置逻辑删除字段名
strategyConfig.setLogicDeleteFieldName("deleted");
// 设置乐观锁字段名
strategyConfig.setVersionFieldName("version");
autoGenerator.setStrategy(strategyConfig);

/* 执行生成器 */
autoGenerator.execute();
}
}
  • 启动生成器,生成代码模版

完成

参考文献

哔哩哔哩——黑马程序员