MyBatis-Plus

MyBatis-Plus

Mybatis-plus

MyBatis-Plus快速入门

MyBatis-Plus->基于MyBatis进行了一系列的开发

配置

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- MyBatis Plus 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version> <!-- 使用最新稳定版本 -->
</dependency>
1
2
3
4
5
6
7
8
@MapperScan("com.anli1.mapper")

public class Case01Application {
public static void main(String[] args) {
SpringApplication.run(Case01Application.class, args);
}
}

官方配置

https://baomidou.com/introduce/

0.了解mybatis封装

1.自动生成sql

MyBatis-Plus 提供了一套自动生成 CRUD(增删改查)操作的方法,这些方法包括:

  • insert():插入数据。
  • deleteById() / deleteBatchIds():根据 ID 或一组 ID 删除数据。
  • updateById():根据 ID 更新数据。
  • selectById() / selectBatchIds():根据 ID 或一组 ID 查询数据。

这些方法避免了手动编写重复的 SQL 语句和 DAO 层代码,显著提高了开发效率。

2.内置分页插件

MyBatis-Plus 内置了分页插件,可以自动处理分页逻辑。开发者只需配置插件,调用相应的分页方法,框架会自动生成分页查询语句并返回分页结果。

3.条件构造器

MyBatis-Plus 提供了 QueryWrapperUpdateWrapper 等条件构造器,使得开发者可以以更加简洁的方式构造复杂的查询或更新条件。例如,可以使用链式方法调用来构建查询条件,替代传统的手动拼接 SQL 的方式:

1
2
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "Tom").ge("age", 20);

后续的就是不怎么用的内容

4.多种插件支持

MyBatis-Plus 提供了一系列插件,以扩展框架的功能,例如:

  • 分页插件:支持自动分页。
  • 性能分析插件:帮助分析 SQL 性能。
  • 多租户插件:支持多租户应用程序开发。
  • 乐观锁插件:支持乐观锁控制,实现高并发场景下的数据安全。
  • 数据权限插件:可以在不同层级上控制数据访问权限。

5.代码生成器

MyBatis-Plus 提供了代码生成器工具,可以根据数据库表结构自动生成实体类、Mapper 接口、Service 类和 Controller 类。这样,大大减少了开发者的工作量,加快了开发速度。

6.逻辑删除

MyBatis-Plus 支持逻辑删除功能,即在删除记录时,不是真的删除数据,而是将记录的某个标志位进行更新。MyBatis-Plus 会自动处理带有逻辑删除标记的数据,使其在查询时被自动排除。

7.自动填充功能

支持自动填充字段功能,例如创建时间、更新时间等字段,可以在插入或更新数据时自动填充指定的字段值。

8.sql性能优化

MyBatis-Plus 对常见的 SQL 语句进行了优化,提高了执行效率。此外,还增强了 SQL 的功能,例如多表关联查询、Lambda 表达式构建器等。

总结

自动 CRUD 操作、内置分页、条件构造器、多种插件支持、代码生成器、逻辑删除、自动填充功能 sql优化

1.BaseMapper类

BaseMapperMyBatis-Plus 提供的一个基础接口,它的作用是为所有的数据库实体类提供通用的 CRUD(增删改查)操作方法。通过继承 BaseMapper,开发者可以避免手动编写大量的重复性代码,大大简化了持久层的开发工作。

84af32c461349faaa0e4f957c97a049b

mapper->继承该方法-这些方法名也是说的非常易懂的

1
2
3
4
// Mapper 接口继承 
BaseMapper public interface UserMapper extends BaseMapper<User> {
// 你可以在这里定义自定义方法
}
2.Mybits 映射Pojo

3c3e138598f90a383add182c550745da

驼峰命名法是一种命名约定,其中每个单词的首字母大写,没有空格或标点符号来分隔单词,例如:camelCase。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@TableName("user") // 指定表名为 'user'
public class User {
@TableId(type = IdType.AUTO) // 指定主键策略
private Long id; // 与表中的 'id' 字段对应

@TableField("name") // 指定映射字段名为 'name'
private String username; // 与表中的 'name' 字段对应

private Integer age; // 与表中的 'age' 字段对应

// Getters and Setters...

}


3.注解@TableName -表名注解

5963a7ca700c1878c285ab9ae2347046

4.主键注解 @Tableid

ed012758973b1755cdcd1d1ddc0e991c

@TableId
private Long id;
属性

242fd1966addaff8b3313118e48981a7

5.普通字段注解@TableField

@TableField(“isMarried”)
private Boolean isMarried;

95e9bd49c3b791c708e964a2f4b15e2a

5fe85caf87e0fab3483354cb7fd499ad

6.常见配置

034876e14a71af1ec8524063ba29c738


mybitspro 也支持手写sql

7441706e396a4cab007d33e7e1dd4469

mybitsx+mybitsplus->可以支持跳转写-具体方法就是mybits

7.条件构造器

1.构造器了解

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

52da0353c64f7992f277a55d5d69307d

Wrapper关系

95aa614360e41a40e6eb3aeb95743c0a

1.AbstractWrapper

提供了where中包含的所有条件构造方法

336fb5b4722bff7397e6c30eb5dea9bf

2.QueryWrapper

拓展了一个select方法,允许指定查询字段

->查询id

47543da4a82f7a8134c43b19b1e10502

3.UpdateWrapper

c1893ba09ded9c12a23470e6000d7325

99ec8027977a2561dadf41ef09a948ad

4.LambdaQueryWrapper

-无论是QueryWrapper还是UpdateWrapper在构造条件的时候都需要写死字段名称,会出现字符串魔法值。这在编程规范中显然是不推荐的。

QueryWrapperUpdateWrapper 常用于构建数据库查询或更新的条件。在使用这些类构造查询条件时,字段名是以字符串形式硬编码在代码中的。

字符串魔法值:直接在代码中写死字段名是一个“魔法值”(Magic String),即无法直观地知道这个字符串代表什么意思,如果需要修改字段名,则必须在代码中找到所有使用该字符串的地方并手动更改。

不安全且容易出错:硬编码的字符串字段名在编译时不会被检查,当字段名拼写错误或发生变化时,可能导致运行时错误(如 SQL 执行失败),但编译器无法检测到这个问题。

难以维护:如果表的字段名称发生更改,代码中的所有字符串字段名都需要手动调整,增加了代码维护的成本。

写死值案例

1
2
3
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "John"); // 使用字符串字段名
queryWrapper.ge("age", 18);

MyBatis-Plus 提供了 LambdaQueryWrapperLambdaUpdateWrapper 来解决上述问题。这些类允许你使用 Lambda 表达式来引用字段,而不是直接使用字符串。这种方式有以下好处:

1
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(User::getName, "John"); // 使用 Lambda 表达式引用字段 lambdaQueryWrapper.ge(User::getAge, 18);

使用 User::getNameUser::getAge 作为字段的引用。User 是实体类,getNamegetAge 是其字段的 Getter 方法。

1b0ffa0bb1d852812ad294a35b8fd888

46be4929662ae5ef628b043e12c85c09

自定义sql-注解

96f49f3a8be18ed697e8915da140bed9

8d725d5559e95de38132857f497800bd

基于注解写sql-是mybitsplus功能

Service接口

1.Service了解

MybatisPlus不仅提供了BaseMapper,还提供了通用的Service接口及默认实现,封装了一些常用的service模板方法。如下

IServiceServiceImpl 是用于简化对数据库操作的通用接口和默认实现。IService 提供了一套通用的服务接口,而 ServiceImpl 则是对这些接口的具体实现。

3dcaf6a956fe9fe726dd0f071b0c71bc

2.新增

13c96b5cebd34752b567c130b95bf94f

3.删除

223e551718256b2c4ccb496ab27fd928

3.更新

15250e865364a0a81ebc28c32da5d578

4.查找单个

4ae94dcbfb1f9c6c65304c24b0345a83

5.查询集合

49306fabfb10f5443ed6af5be333fd1e

6.计数

c48dc029d0bd68c01a7dfbe8b5a6fc45

7.分页查询

1cd184ca76dc2163ff33cff11f550075

Lambda

MyBatis(包括 MyBatis-Plus)中使用了 Lambda 表达式来简化查询操作,使代码更加简洁和易于维护。Lambda 表达式通常与 LambdaQueryWrapperLambdaUpdateWrapper 一起使用,提供一种类型安全的方式来编写条件查询和更新语句。

1.LambdaQueryWrapper

LambdaQueryWrapper 用于构建查询条件。它利用 Java 8 的 Lambda 表达式特性,使条件构造更加直观和安全。以下是一些常用的方法:\

eq:相等查询

ne:不等于查询

gt:大于查询

ge:大于等于查询

lt:小于查询

le:小于等于查询

like:模糊查询

notLike:不匹配查询

likeLeft:左匹配查询

likeRight:右匹配查询

between:在区间内查询

notBetween:不在区间内查询

isNull:字段为空查询

isNotNull:字段不为空查询

in:包含查询

notIn:不包含查询

orderByAsc:升序排序

orderByDesc:降序排序

2.LambdaUpdateWrapper

set:设置要更新的字段和值

eq:相等查询

ne:不等于查询

gt:大于查询

ge:大于等于查询

lt:小于查询

le:小于等于查询

like:模糊查询

between:在区间内查询

isNull:字段为空查询

isNotNull:字段不为空查询

1
2
3
4
5
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(User::getId, 1)
.set(User::getName, "李四")
.set(User::getAge, 25);
userMapper.update(null, updateWrapper);
3.lambda简化

如果你不想在 MyBatis-Plus 中每次都使用 new LambdaQueryWrapper<>()new LambdaUpdateWrapper<>(),你可以使用 MyBatis-Plus 提供的静态方法来简化代码。MyBatis-Plus 的 Wrappers 类提供了多个静态方法,用于构建 Lambda 表达式的查询和更新条件。

MyBatis-Plus 提供了 Wrappers.lambdaQuery()Wrappers.lambdaUpdate() 方法来创建 LambdaQueryWrapperLambdaUpdateWrapper 的实例。这些方法使代码更加简洁,省去了显式创建对象的步骤。

23977048b3aead660e100eb55b7391b2

c243ec58a30cfb1eaaa8fe38a934fd14

68eda2f47849ac7f17f343f9d71147bf

bbffabb2a6d9fd54b8984cbe194d1457

改造根据id修改用户余额的接口,要求如下

  • 如果扣减后余额为0,则将用户status修改为冻结状态(2)

467e0f04ce771a195c18e1c64970a3ae

动态sql

mybits批量处理

IService中的lambdaUpdate方法可以非常方便的实现复杂更新业务

—也就是不需要构造条件-直接可以用lambda-进行查询

Mybits批处理

逐条插入

101b580959e40e749e63af58e1ac2bd9

mybits批处理

866ee7682e72520e58686b6b1bc60e46

每1000条批量插入一次

为什么mybits插入速度就快

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
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveBatch(Collection<T> entityList, int batchSize) {
//传入集合和集合大小

String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
获取预处理sql

return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
}
->
public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
Assert.isFalse(batchSize < 1, "batchSize must not be less than one");///断言语句
///三元运算
return
!CollectionUtils.isEmpty(list)//检查集合是否为空
&& executeBatch(entityClass, log, sqlSession -> {
int size = list.size();
int idxLimit = Math.min(batchSize, size);
int i = 1;
for (E element : list) {
consumer.accept(sqlSession, element);
if (i == idxLimit) {
sqlSession.flushStatements();
idxLimit = Math.min(idxLimit + batchSize, size);
}
i++;
}
});

executeBatch(entityClass, log, sqlSession -> { … }): 这是一个方法调用,调用了名为 executeBatch 的方法,并传递了 entityClass、log 和一个 Lambda 表达式作为参数。Lambda 表达式中的代码块将会在 executeBatch 方法内部执行。

Lambda 表达式内部的逻辑:

首先,获取集合 list 的大小,并将其存储在变量 size 中。
然后,计算循环的上限索引 idxLimit,它等于批处理大小 batchSize 和集合大小 size 中的较小值。
接着,初始化变量 i 为 1,用于追踪当前处理的元素索引。
在循环中,遍历集合 list 中的每个元素 element:
    使用 consumer.accept(sqlSession, element) 方法处理当前元素,其中 consumer 是一个函数接口,用于执行特定的操作。
    如果当前处理的索引 i 等于上限索引 idxLimit,则调用 sqlSession.flushStatements() 方法来刷新 SQL 语句,并更新上限索引 idxLimit 为下一个批次的上限索引。
    最后,增加索引变量 i 的值,进入下一轮循环。

整个 Lambda 表达式的执行结果将作为 executeBatch 方法的返回值。

}

以发现其实MybatisPlus的批处理是基于PrepareStatement的预编译模式,然后批量提交,最终在数据库执行时还是会有多条insert语句,逐条插入数据。SQL类似这样:

0d893a2bdab9ed10ad0c7284e6823446

——-开启重新批处理

e5d8dd6fc91bf3b8183f433d705a8485****

accd1ecdecd550e717eaffb8a07860cc

mybitsplus->代码生成

在使用MybatisPlus以后,基础的Mapper、Service、PO代码相对固定,重复编写也比较麻烦

640804c8b4ef9653c763c7c457d5c1e9

8be53fe79baa68053e1013376f8ea342

42bb2850b64b4a5daa22cf5a3e19e92a

465db4382ca68f36c25c79a80bbce054

MybitsPlus静态

有的时候Service之间也会相互调用,为了避免出现循环依赖问题,MybatisPlus提供一个静态工具类:Db,其中的一些静态方法与IService中方法签名基本一致,也可以帮助我们实现CRUD功能

c1f46709369d86eee7c03df671545992

59a15e1243bd819dbc3e3d4869dd7b79

案例

改造根据id用户查询的接口,查询用户的同时返回用户收货地址列表

c9982422351f6ecc277ededc0e803296

逻辑删除优化

edb312802503c8139e9606f8ae74f0d8

确实
比如云盘项目-就是要过滤这些条件

c7bda4e8f8266db45e4908e922627b8a

配置逻辑删除

0dd9aceaa2940ed98150df3ea6b48312

查询测试

64779cb8ce59b7e93069adc874ce93ed

通用枚举

60a018a6f80a6f46b6c5c4f5bf7fb176

mybits->提供枚举类型与数据库类型自动转换

MyBatis-Plus 通过注解 @EnumValue 指定数据库字段和枚举字段的映射。

cb75a3b930d23430174c125921d14601


c4934929e1a9c7b79d79f04adf975105

同时,为了使页面查询结果也是枚举格式,我们需要修改UserVO中的status属性:

28cfbac5f5fa1ffc563eb851a3f65f25

0—会自动根据数字-对应正常或者冻结

json类型处理器

在 MyBatis-Plus 中,我们可以使用 JacksonTypeHandler 类型处理器来自动将 JSON 数据库字段与 Java 对象之间进行转换,这样就不需要手动进行字符串与 JSON 对象之间的转换了。JacksonTypeHandler 使用了 Jackson 库来进行 JSON 序列化和反序列化操作。

在 MyBatis-Plus 中,我们可以使用 JacksonTypeHandler 类型处理器来自动将 JSON 数据库字段与 Java 对象之间进行转换,这样就不需要手动进行字符串与 JSON 对象之间的转换了。JacksonTypeHandler 使用了 Jackson 库来进行 JSON 序列化和反序列化操作。

假设你有一个 user 表,其中 info 字段是 JSON 类型。在 User 实体类中,我们希望将 info 映射为一个 Java 对象(如 Map 或一个自定义的 Java 类),而不是 String。我们可以使用 JacksonTypeHandler 来实现这种自动转换。

在实体类的对应字段上使用 @TableField 注解,并指定 typeHandlerJacksonTypeHandler

如果 info 字段是一个 Map 或者自定义对象类型,JacksonTypeHandler 会自动完成 JSON 与 Java 对象之间的转换。

6d0855f286d0ffdb19096463987947fb

JacksonTypeHandler 会将数据库中的 JSON 数据自动转换为 UserInfo 对象,并且在保存时会自动将 UserInfo 转换为 JSON 字符串。

分页查询

1.配置分页插件

12944f422088ff0097b7beb2b0d835d3

1
2
3
4
5
6
7
8

@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}

PaginationInterceptor 插件是 MyBatis-Plus 提供的分页插件,它会自动处理分页逻辑,支持多种数据库。

2.分页api
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class UserService {

@Autowired
private UserMapper userMapper;

public Page<User> getUsersByPage(int currentPage, int pageSize) {
// 创建 Page 对象
Page<User> page = new Page<>(currentPage, pageSize);

// 创建 QueryWrapper 对象
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id"); // 按照 id 降序排列

// 执行分页查询
return userMapper.selectPage(page, queryWrapper);
}
}

使用 Page 类创建了一个分页对象,并指定了当前页码和每页显示的记录数。selectPage 方法会执行分页查询,并将结果封装在 Page 对象中返回。

3.,Page 对象的属性

Page 对象包含以下属性:

  • **current**:当前页码。
  • **size**:每页显示的记录数。
  • **total**:总记录数。
  • **pages**:总页数。
  • **records**:当前页的数据记录列表。
1
2
3
4
Page<User> userPage = userService.getUsersByPage(1, 10);
List<User> users = userPage.getRecords(); // 当前页的数据记录
long total = userPage.getTotal(); // 总记录数
long pages = userPage.getPages(); // 总页数

MyBatis-Plus
http://example.com/2024/09/14/MybitsPlus/
作者
John Doe
发布于
2024年9月14日
许可协议