【MyBatisPlus】
概述
为什么学
学习每门新技术之前我们都需要先问自己一个问题: 学它干嘛?!
MyBatisPlus是在MyBatis基础上进行了一系列的简化操作,可以节省我们大量的工作时间,自动化完成所有的CRUD操作(可以偷懒不写SQL语句)。
同类型框架:JPA、th-mapper
在了解了为什么要学习它之后我们开始正式的学习之旅~~~
先去官网康一康(好习惯!):https://mp.baomidou.com/
简介
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
快速入门
https://mp.baomidou.com/guide/quick-start.html#初始化工程
使用第三方组件:
- 导入对应依赖
- 研究依赖如何配置
- 研究代码如何编写
- 提高拓展技术能力
1.创建数据库 mybatis_plus
id | name | age | |
---|---|---|---|
1 | Jone | 18 | test1@baomidou.com |
2 | Jack | 20 | test2@baomidou.com |
3 | Tom | 28 | test3@baomidou.com |
4 | Sandy | 21 | test4@baomidou.com |
5 | Billie | 24 | test5@baomidou.com |
1 | DROP TABLE IF EXISTS user; |
2.初始化项目(使用SpringBoot初始化)
3.导入依赖
==注意!mybatis-plus和mybatis只能导入一个,否则容易发生包冲突==
1 | <dependency> |
4.配置数据源
1 | spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?userUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 |
5.编写三层架构
以前:pojo -> dao(连接mybatis,配置mapper.xml) -> service -> controller
现在:
pojo
1
2
3
4
5
6
7
8
9
10
11
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}mapper接口
1
2
3
4//继承父类BastMapper<>
public interface UserMapper extends BaseMapper<User> {
}我们来简单看一看这个
BaseMapper<>
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
35public interface BaseMapper<T> {
int insert(T var1);
int deleteById(Serializable var1);
int deleteByMap(; Map<String, Object> var1)
int delete(; Wrapper<T> var1)
int deleteBatchIds(; Collection<? extends Serializable> var1)
int updateById(; T var1)
int update(; T var1, Wrapper<T> var2)
T selectById(Serializable var1);
List<T> selectBatchIds(; Collection<? extends Serializable> var1)
List<T> selectByMap(; Map<String, Object> var1)
T selectOne(; Wrapper<T> var1)
Integer selectCount(; Wrapper<T> var1)
List<T> selectList(; Wrapper<T> var1)
List<Map<String, Object>> selectMaps(; Wrapper<T> var1)
List<Object> selectObjs(; Wrapper<T> var1)
IPage<T> selectPage(IPage<T> var1, ; Wrapper<T> var2)
IPage<Map<String, Object>> selectMapsPage(IPage<T> var1, ; Wrapper<T> var2)
}使用
1
2
3
4
5
6
7
8
9
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MybatisPlusApplicationTests {
UserMapper userMapper;
void contextLoads() {
//参数是一个 Wrapper(条件构造器)
List<User> users = userMapper.selectList(null);
//语法糖
users.forEach(System.out::println);
}
}
配置日志
我们所有的sql现在是不可见的,我们需要知道他们是怎么执行的,所有需要配置日志
1 | #配置日志 |
配置完毕日志之后,后面的学习就需要注意自动生成的SQL了!
CRUD扩展
插入操作
1 |
|
主键生成策略
分布式系统唯一ID生成方案汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html
数据库自增长序列或字段
1
2
private Long id;同时需要把数据库中的 自增 勾选上!
UUID
UUID变种
Redis生成ID
Twitter的snowflake算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。
更新操作
1 |
|
所有sql都是自动动态配置的!
自动填充
阿里巴巴开发手册:所有的数据库表中,gmt_create
、gmt_modified
几乎都要配置上!(需要自动化)
创建时间、修改时间……这些操作一般都是自动化完成的,不希望手动进行更新!
1.数据库级别
在表中新增字段
create_time
、update_time
再次测试插入方法(先同步实体类)
2. 代码级别
删除数据库的默认值、更新操作
实体类的字段属性上增加注解
1
2
3
4
private Date createTime;
private Date updateTime;编写处理器来处理注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//一定不要忘记把处理器加到容器当中
public class MyMetaBojectHandler implements MetaObjectHandler {
public void insertFill(MetaObject metaObject) {
log.info("start insert fill.....");
//default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
this.setFieldValByName("createTime", new Date(), metaObject);
}
public void updateFill(MetaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
乐观锁
面试常客!!!
乐观锁:顾名思义,十分乐观,总是认为不会出现问题,无论干什么都不会去上锁。如果出现了问题,再次更新值测试。
悲观锁:顾名思义,顾名思义,总是认为会出现问题,无论干什么都会去上锁。再去操作。
我们主要研究乐观锁机制!
意图:当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
1 | -- A线程 |
测试一下乐观锁插件
给数据库中添加
version
字段实体类加对应字段
1
2//乐观锁version注解
private Integer version;注册组件
1
2
3
4
5
6
7
8
9
10
11
12//包扫描可以放在配置类中
public class MybatisPlusConfig {
//注册乐观锁插件
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}特别说明:
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在
update(entity, wrapper)
方法下,wrapper
不能复用!!!
测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void optimisticLocker() {
//线程一
User user1 = userMapper.selectById(1L);
user1.setName("T1");
user1.setEmail("123456@qq.com");
//线程二
User user2 = userMapper.selectById(1L);
user2.setName("T2");
user2.setEmail("123456@qq.com");
//模拟线程二的插队操作
userMapper.updateById(user2);
//如果没有乐观锁,就会覆盖插队线程的值
userMapper.updateById(user1);
}执行结果:
结论:多线程下的操作一定要加锁
查询操作
1 | //单个查询 |
分页查询
- 原始的使用 limit 进行分页
- pageHelper 第三方插件
- MybatisPlus 内置了分页插件
使用方法:
- 导入分页插件
1 |
|
简化版:
1 |
|
- 直接使用Page对象
1 |
|
删除操作
删除操作大致与查询操作相同
1 | //单个查询 |
逻辑删除
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除,而是通过一个变量让它失效(deleted = 0 => deleted = 1)
管理员可以查看被删除的记录!防止数据的丢失,类似于回收站的功能
测试:
数据表中增加
deleted
字段pojo中增加字段
1
2
private int deleted;配置
1
2
3
4
5//3.1.1版本之后不再需要这一步
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}1
2
3
4
5
6mybatis-plus:
global-config:
db-config:
logic-delete-field: flag #全局逻辑删除字段值 3.3.0开始支持,详情看下面。
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
本质走的是更新操作,更新了 deleted
的值
效果:
1 | -- 删除 |
性能分析插件
在平时开发中会遇到一些慢 sql
MybatisPlus也提供了性能分析插件,如果超过某个时间,就停止运行!
导入插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//Spring boot方式
public class MybatisPlusConfig {
/**
* SQL执行效率插件
*/
// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
}注意!
要在SpringBoot中配置环境为 dev 或者 test
参数说明:
- 参数:maxTime SQL 执行最大时长,超过自动停止运行,有助于发现问题。
- 参数:format SQL SQL是否格式化,默认false。
- 该插件只用于开发环境,不建议生产环境使用。
测试使用
……
条件构造器
==十分重要:Wrapper==
isNotNull、ge
1 |
|
eq
1 |
|
between
1 |
|
like、notLike、LeftLike、RightLike
1 |
|
inSql
1 |
|
自动代码生成器
1 | package com.wxshhh; |
神器!!!
完结撒花~~~~~~~~~
狂神,永远滴神!!!
参考
狂神说Java:https://www.bilibili.com/video/BV17E411N7KN
MybatisPlus官网:https://mp.baomidou.com/guide/quick-start.html#初始化工程
分布式系统唯一ID生成方案汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html