Mybatis-Plus详解,不懂得这里都有

狂神小粉丝

  • 简介
  • 特性
  • 快速入门
  • 配置日志
  • 主键生成策略(雪花算法)
  • 自动填充
  • 乐观锁/悲观锁
  • 查询操作
  • 删除操作
    • 逻辑删除
  • 性能分析打印插件
  • 条件构造器Wrapper
  • 代码生成器

简介

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

愿景
我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

Mybatis-Plus详解,不懂得这里都有_第1张图片

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速入门

官方快速开始
0、建数据库

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, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');

1、新建Springboot项目

2、导入相关依赖
pom.xml


 <dependency>
     <groupId>org.projectlombokgroupId>
     <artifactId>lombokartifactId>
     <optional>trueoptional>
 dependency>
 
 <dependency>
     <groupId>com.baomidougroupId>
     <artifactId>mybatis-plus-boot-starterartifactId>
 dependency>
 
 <dependency>
     <groupId>mysqlgroupId>
     <artifactId>mysql-connector-javaartifactId>
 dependency>

注:尽量不要同时导入Mybatis和Mybatis-plus包!版本有差异

3、配置文件
application.yml

# DataSource Config
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://test :3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

4、写实体类
Mybatis-Plus详解,不懂得这里都有_第2张图片

5、写Mapper
Mybatis-Plus详解,不懂得这里都有_第3张图片
6、测试
Mybatis-Plus详解,不懂得这里都有_第4张图片

配置日志

application.yml

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

主键生成策略(雪花算法)

分布式唯一id生成方案:https://www.cnblogs.com/myseries/p/10789386.html

id上添加@TableId可以设置主键生成规范。
Mybatis-Plus详解,不懂得这里都有_第5张图片

自动填充

在这里插入图片描述
创建时间、修改时间!这些操作我们希望是自动化完成!

方式一:通过数据库修改

1、添加字段
在这里插入图片描述在这里插入图片描述
2、更改实体类
Mybatis-Plus详解,不懂得这里都有_第6张图片
3、测试
Mybatis-Plus详解,不懂得这里都有_第7张图片
Mybatis-Plus详解,不懂得这里都有_第8张图片
可以看到时间已经自动添加上去了。

方式二:代码级别

官方文档自动填充

1、实体类的字段属性上添加注解

@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;

**2、编写处理器 **

@Component      //千万不要忘记吧自定义的组件添加到Ioc容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入时候的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("gmtCreate",new Date(),metaObject);
        this.setFieldValByName("gmtModified",new Date(),metaObject);
    }

    //更新时候的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("gmtModified",new Date(),metaObject);
    }
}

3、测试更新,观察时间即可

 @Test
    void insert(){
        User user = new User();
        user.setAge(3);
        user.setName("熊二");
        user.setEmail("[email protected]");

        userMapper.insert(user);
    }

Mybatis-Plus详解,不懂得这里都有_第9张图片

乐观锁/悲观锁

在面试过程中,我们经常会被问到乐观锁悲观锁。其实非常简单

  • 乐观锁:顾名思义非常乐观,他总是认为不会出现问题,无论何时都不会上锁。如果出现问题,再次更新时测试。
  • 悲观锁:顾名思义非常悲观,他认为总是会出现问题,无论干什么都会上锁,然后再去执行操作。

官方乐观锁插件

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
A,B线程同时执行
假若A 线程执行完成,那么全局变量version+=1,那么B 线程就会执行失败。
由此便可以实现乐观锁。

--A线程
update user set name = "xionger" , version = version + 1
where id = 2 and version = 1

--B线程
update user set name = "xionger" , version = version + 1
where id = 2 and version = 1

MP测试乐观锁插件

1、给数据库中添加version字段

2、同步实体类

@Version    //乐观锁的version注解
private int version;

3、注册组件

@Configuration		//配置类
public class MybatisPlusConfig {
    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

4、测试

  • 单线程测试乐观锁成功
    // 测试乐观锁成功
    @Test
    void testOptimisticLockerInterceptor(){
        // 查找用户信息
        User user = userMapper.selectById(1L);
        // 修改用户信息
        user.setName("xionger");
        user.setEmail("[email protected]");
        // 执行更新操作
        userMapper.updateById(user);
    }
    
  • 多线程乐观锁:插入失败
    // 测试乐观锁失败;多线程下
    @Test
    void testOptimisticLockerInterceptor2(){
    
        // 开启线程user1
        User user1 = userMapper.selectById(1L);
        user1.setName("xionger1");
        user1.setEmail("[email protected]");
    
        // 模拟线程user2执行了插队操作
        User user2 = userMapper.selectById(1L);
        user2.setName("xionger2");
        user2.setEmail("[email protected]");
        userMapper.updateById(user2);
        
        // 执行线程user1的更新操作
        userMapper.updateById(user1);
    }
    

在这里插入图片描述
由此可见,user2执行完毕后,并没有执行user1的更新操作,说明乐观锁生效。

查询操作

查询单个用户

// 查询单个用户
    @Test
    void selectPer(){
        System.out.println(userMapper.selectById(1L));
    }

查询多个用户

// 查询多个用户
    @Test
    void selectMany(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
        users.forEach(System.out::println);
    }

按条件查找

// 按条件查询1:使用map操作
    @Test
    void selectMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","熊二");
        map.put("age",3);

        userMapper.selectByMap(map);
    }

分页查询

官方分页插件文档

  • 配置文件
@Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
  • 执行操作
// 分页查询:limit分页/pageHelper第三方插件/MP内置了分页插件https://mp.baomidou.com/guide/page.html
    @Test
    void selectPage(){
        Page<User> page = new Page<>(1,5);
        System.out.println(userMapper.selectPage(page, null));
    }

删除操作

删除单个

// 测试单个删除
    @Test
    void deletePer(){
        userMapper.deleteById(1L);
    }

批量删除

// 测试list批量删除
    @Test
    void deleteMany(){
        userMapper.deleteBatchIds(Arrays.asList(1L,2L));
    }

按条件删除

// 测试map按条件删除
    @Test
    void deleteMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","熊二");
        map.put("age",3);
        userMapper.deleteByMap(map);
    }

逻辑删除

逻辑删除官方文档

物理删除:在数据库中删除
逻辑删除:在数据库中没有删除,而是通过一个变量表示他失效

管理员可以查看被删除的记录!!!(逻辑删除),方式数据的丢失,类似于回收站。

1、在数据库中添加delete字段

在这里插入图片描述

2、同步实体类

@TableLogic
    private int flag;

3、配置
application.yml

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

4、测试使用

Mybatis-Plus详解,不懂得这里都有_第10张图片
由此可见调用的是删除操作,可是实际上执行的是更新操作。

Mybatis-Plus详解,不懂得这里都有_第11张图片
而查询的时候,则查询的是flag=0的信息,也就是没有被逻辑删除的信息。

性能分析打印插件

因为我们在平时开发中会遇到慢sql的问题,基于此MyBatis Plus就提供了性能分析插件,超过这个时间就停止运行。

先贴出官方性能分析文档

Mybatisplus3.2.0以上就不支持本身的性能分析插件(PerformceInterceptor),支持p6spy组件,下面我们就p6spy进行分析。

一定要注意版本问题!!!

1、导入maven依赖
pom.xml

<dependency>
   <groupId>p6spygroupId>
    <artifactId>p6spyartifactId>
    <version>3.8.6version>
dependency>

2、编写yml配置文件
application.yml

  • 关键点1:url需要加上p6spy 固定的是jdbc:p6spy:数据库名…
  • 关键点2:driver-class-name指定的是p6spy的驱动
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:p6spy:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&charcterEncoding=UTF-8
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver

3、增加p6spy的核心配置文件spy.properties

  • 注意MybatisPlus版本,3.2.1是一个坎~
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2

4、直接测试

在这里插入图片描述
可以看到运行时间。

条件构造器Wrapper

我们可以使用他来代替一些复杂的sql

写贴出官方条件构造器文档。

test1:普通条件查询

@Test
    void contextLoads() {
        // 查询name不为空,email不为空,年龄大于等于12的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper
                .isNotNull("name")
                .isNotNull("email")
                .ge("age",12);
        userMapper.selectList(wrapper).forEach(System.out::println);
    }

test2:区间查询

@Test
void test2(){
    // 查询年龄在20~30岁之间的用户的数量
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age",20,30);
    Integer integer = userMapper.selectCount(wrapper);
}

test3:模糊查询

// 模糊查询
@Test
void test3() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
            .notLike("name","a")   //name中不包含a的字段
            .likeRight("email","t");    //email以t开头的字段

    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
    maps.forEach(System.out::println);
}

test4:嵌套查询

// 嵌套查询
    @Test
    void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper
                .inSql("id","select id from user where id < 3");

        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);
    }

对应的Sql语句为:

SELECT 
	id,gmt_modified,flag,name,gmt_create,version,email,age 
FROM 
	user 
WHERE 
	flag=0 
		AND 
	(id IN (select id from user where id < 3))

在这里插入图片描述
关于其他的一些官方文档里都有,我就在这里测试了。
Mybatis-Plus详解,不懂得这里都有_第12张图片

代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

先贴出官方代码生成器文档

MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖。

1、导入maven依赖
pom.xml

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.3.2</version>
</dependency>

2、连接数据库
application.xml

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:p6spy:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
  profiles:
    active: dev

3、配置自己要用到的一些配置类

由于代码生成器要生成一些具有 逻辑删除、乐观锁、分页查询 之类的模块。而这些模块需要自己进行配置。具体的配置在上文。其实就是把组件添加进spring托管。

  • 例如下面这些
//注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    // 注册分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

4、编写具体操作,执行

public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");	//将代码生成在这个目录下
        gc.setAuthor("熊二");
        gc.setOpen(false);
        // gc.setSwagger2(true); 实体属性 Swagger2 注解
        mpg.setGlobalConfig(gc);

        // 数据源配置,将步骤二的数据库信息粘贴在下方
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent("com.xionger");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("表名1","表名2"...);		//要生成哪些表的代码
        strategy.setNaming(NamingStrategy.underline_to_camel);		//设置包的命名规则,这里为下划线转驼峰命名
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);	//列的名字
        strategy.setEntityLombokModel(true);		//自动lombok
        strategy.setLogicDeleteFieldName("deleted");	//设计逻辑删除
		//自动填充配置
		TableFill gmtCreate = new TableFill("gmt_create",FieldFill.INSERT);
		TableFill gmtModified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);
		ArrayList<TableFill> tableFills = new ArrayList<>();
		tableFills.add(gmtCreate);
		tableFills.add(gmtModified);
		strategy.setTableFillList(tableFills);			//自动填充
		strategy.setVersionFieldName(""version);		//乐观锁        
        
        
        mpg.setStrategy(strategy);
		
		// 执行代码生成器
        mpg.execute();
    }

到这里MyBatis-Plus的基本内容就差不多了。good_good_study day_day_up
Mybatis-Plus详解,不懂得这里都有_第13张图片

你可能感兴趣的:(spring)