MyBatis-Plus
概述
官方网址:https://mp.baomidou.com/guide/
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,它在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
它是 MyBatis 最好的搭档,就好像魂斗罗中的 1p,2p 两个玩家一样。
特性:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
SpringBoot 整合 MyBatis-Plus
创建数据库
CREATE DATABASE mybatis_plus
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(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');
创建空的 SpringBoot 项目,引入需要的依赖
<!-- 数据库连接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!-- mybatis_plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
连接数据库
# 基础的配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&useSSL=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: 123456
创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
创建mapper类,让 mapper 类继承 BaseMapper ,泛型是对应的实体类
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
在启动类中添加扫描 mapper
@SpringBootApplication
@MapperScan("com.czx.mapper") //注意:一定要扫描
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}
至此,我们已经写好了全部的 CRUD ,不信? 我们来测试。
使用 junit 编写测试代码,首先查出数据库中所有的 user
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
看查询结果,所有的用户都被查寻出来了,我们并没有写任何 sql 语句,那是谁帮我们写的呢?当然是 MyBatis-Plus 帮我们写的!(createTime 和 updateTime 稍后再说)
我们再测试一下插入功能
@Test
public void testInsert(){
User user = new User();
user.setName("Czx");
user.setAge(7);
user.setEmail("12345678@qq.com");
userMapper.insert(user);
}
我们发现,我们在执行插入操作的时候,id 插入的是很长一串无规则的数据,但我们并没有给 id ,那么这个 id 又是哪里来的。
这里要说说 MyBatis-Plus 在实体类中使用的注解了 @TableId()
现在我们对 id 添加如下注解,再来分析注解的作用
//插入数据时自增的方式
@TableId(type=IdType.AUTO)
private Long id;
我们来分析源码,按住 ctrl 依次点击红框
我们发现,在 IdType中,有好几个参数。这些参数就是 id 产生时,所使用的。
- auto:按序自增,在使用这一项时,数据库表中 id 必须勾选自增选项
- none:当表没有主键时使用
- input:插入操作时,手动给定 id
- id_worker、uuid、id_worker_str 这三项都是自动生成 id ,其中默认的是 id_worker
那么 id_worker 是怎样生成 id 的?采用的是雪花算法
来产生 id 的。
雪花算法:
1、第一位 占用1bit,其值始终是0,没有实际作用。
2、时间戳 占用41bit,精确到毫秒,总共可以容纳约69年的时间。
3、工作机器id 占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,做多可以容纳1024个节点。
4、序列号 占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID。
这样,id 的生成我们就搞清楚了。下面我们进行改这个操作
@Test
public void testUpdate(){
User user = new User();
user.setId(1278951504018575367L);
user.setAge(15);
userMapper.updateById(user);
}
}
年龄已经修改成了 15岁。
通过日志,我们可以看出,MyBatis_Plus 替我们组合了动态 sql
阿里巴巴Java开发手册中对数据库的代码编写,做了强制要求,必须要有 id、gmt_create、gmt_modified 这三项。现在我们来更新数据库,在数据库中添加 create_time,update_time 两项来表示数据库数据的创建时间和更改时间。
接下来我们就按照要求改变我们的代码,首先更改数据库
接着,同步实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//插入数据时自增的方式
@TableId(type=IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
这里出现了 @TableField()注解,我们来说说这个注解的作用。
这个参数就是用来标注什么情况下更新字段数据的。举个例子:上面的两个参数是 Date 型的,时间是时时刻刻在变化的,对某一操作的时间点进行记录,每一次操作记录一次,那么这个参数就需要不断的更新。
点进源码,我们发现它还是有几个参数
default:默认不更新该字段的数据
insert:在插入操作时,更新字段数据
update:在更新操作时,更新字段数据
insert_update:在插入和更新的时候都更新字段数据
接着我们分包,再创建实体类,编写更新策略。
首先去实现 MetaObjectHandler 接口,重写接口中的两个方法,一个是插入时的策略,一个是更新时的策略。
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//在执行插入功能时,进行自动填充的策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("insert start ...");
//default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//在执行更新时,进行自动填充的策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("update start...");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
我们来解释一下方法
setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
setFieldValByName 有三个参数:
fieldName 是想更新的字段
fieldVal 是更新成什么样,所以它给了 Object 类
最后一个是固定的 metaObjec
所以,我们对字段的更新就成了如下:
对于插入操作,在操作时,将插入数据的 创建时间、更新时间 一同更新
对于更新操作,在操作时,将数据的 更新时间 进行更新
下面我们来测试
@Test
public void testInsert(){
User user = new User();
user.setName("Czx");
user.setAge(7);
user.setEmail("12345678@qq.com");
userMapper.insert(user);
}
@Test
public void testUpdate(){
User user = new User();
user.setId(1278951504018575369L);
user.setAge(500);
userMapper.updateById(user);
}
先执行插入操作,创建时间和更改时间同步更新了
再执行修改操作,创建时间没有改变,更新时间变化了。
这种写法在时间的更新上很常用,我们下篇再见…(∩_∩)~