Mybatis-Plus

Mybatis-Plus

1、MybatisPlus

简介

​ 一个更加简化的jdbc访问数据库的一个框架,是mybatis的升级版,mybatis虽然简化了JDBC访问数据库的操作,但是还是要写SQL语句,而mybatisplus就需要我们写SQL语句了,只要我们继承一个类即可BaseMapper<实体类名称>,一旦继承了该类所有的CRUD操作都已经自动帮我们编写完了。

  • **官网:**https://mp.baomidou.com/

特性:

  • 无入侵。损耗小
  • 强大的CRUD操作
  • 支持lombok形式调用
  • 支持主键自动生成
  • 支持ActiveRecord模式
  • 支持自定义全局通用操作
  • 内置代码生成器:采用代码或者Maven插件可快速生成Mapper、model、service、controller层代码,支持模板引擎,更有超多自定义配置
  • 内置分页插件且支持多种数据库
  • 内置性能分析插件:可输出sql语句以及其执行时间
  • 内置全局拦截插件

2、快速入门

数据库环境

  1. 创建数据库 Mybatis_plus
  2. 创建表

使用MybatisPlus的步骤

  1. 导入依赖
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>
<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

**说明:**尽量不要同时导入Mybatis和MybatisPlus 版本差异

  1. 配置数据源(application.yaml)
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis-plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
  1. pojo
package com.example.mybatisplus.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class plus {
    private Integer id;
    private String name;
    private String password;
}
  1. mapper(dao)
package com.example.mybatisplus.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplus.pojo.plus;
import org.springframework.stereotype.Repository;

@Repository
//将我们的mapper继承mybatis-plus的BaseMapper类即可
public interface PlusMapper extends BaseMapper<plus> {
    //继承了该类基本的CRUD操作都已经自动帮我们生成了,只需调用即可
    //注意我们需要在主启动类上加上扫描该包的注解 @MapperScan()

}

只需将我们的mapper继承mybatis-plus的BaseMapper类即可,继承了该类基本的CRUD操作都已经自动帮我们生成了,只需调用即可。 注意:需在主启动类上加上扫描该包的注解 @MapperScan()

在这里插入图片描述

  1. test
package com.example.mybatisplus;

import com.example.mybatisplus.dao.PlusMapper;
import com.example.mybatisplus.pojo.plus;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class MybatisPlusApplicationTests {

    @Autowired
    PlusMapper plusMapper;

    @Test
    void contextLoads() {
        List<plus> pluses = plusMapper.selectList(null);
        pluses.forEach(System.out::println);
    }

    @Test
    //条件查询
    void contextLoads() {
        //批量查询
        List<plus> pluses1 = plusMapper.selectBatchIds(Arrays.asList(1, 2));
        //map条件查询
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","qiumin");
        map.put("name","changsha");
        List<plus> pluses2 = plusMapper.selectByMap(map);
        //查询所有
        List<plus> pluses = plusMapper.selectList(null);
        pluses.forEach(System.out::println);
    }

}

  • SQL语句mybatis-plus已经帮我们写好了,方法也写好了,我们只需要调用方法

3、配置日志

由于我们现在使用了mybatis-plus,SQL语句在底层就帮我们生成好了,我们可以通过日志来看到底是怎样执行的!

  • 配置日志(控制台打印)
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

在这里插入图片描述

4、CRUD

//注入
@Autowired
PlusMapper plusMapper;

插入

@Test
void contextLoads() {
    List<plus> pluses = plusMapper.selectList(null);
    plus plus=new plus(3,"haha","888888");
    //插入
    plusMapper.insert(plus);
    pluses.forEach(System.out::println);
}
//插入时没有设置id主键时默认主键填充为 ID_WORKER(3)

更新

@Test
void contextLoads() {
    plus plus=new plus();
    plus.setId(3);
    plus.setName("hahaha");
    //更新
    plusMapper.updateById(plus);
    List<plus> pluses = plusMapper.selectList(null);
    pluses.forEach(System.out::println);
}

//更新时会通过条件自动拼接Sql,即动态SQL

删除

    @Test
    void contextLoads() {
        plus plus=new plus();
        plus.setId(3);
        //删除三号用户
        plusMapper.deleteById(plus);
        List<plus> pluses = plusMapper.selectList(null);
        pluses.forEach(System.out::println);
    }

5、主键生成策略

**分布式系统唯一id生成参考文档:**http://www.cnblogs.com/haoxinyue/p/5208136.html

  • 雪花算法

主键自增

在类字段上配置属性自增:

  1. 实体字段上 @TableId(type = IdType.AUTO)
  2. 数据库字段上一定是自增的。默认为:ID_WORKER(3)主键填充策略

在这里插入图片描述

  • 源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.baomidou.mybatisplus.annotation;

public enum IdType {
    AUTO(0),  //自增策略
    NONE(1),  //没有
    INPUT(2), //自己手动输入
    ASSIGN_ID(3), //MySQL默认的主键填充策略,全局唯一
    ASSIGN_UUID(4);  //UUID填充策略,全局唯一

    private final int key;

    private IdType(int key) {
        this.key = key;
    }

    public int getKey() {
        return this.key;
    }
}

6、自动填充时间

表的创建时间、修改时间,这些我们可以通过一些必要的设置实现自动填充

方式一:数据库级别的操作

  • 在表中创建两个字段,分别用于创建时间和更新时间 create_time update_time

在这里插入图片描述

注意:这里由于数据库的版本不同,该数据类型也不相同

  • 5.7版本以上的MySQL版本才有更新的选项,且数据类型为datetime,在勾选更新即可
  • 5.7之前的的版本数据类型为timestamp,且没有更新选项

方式二:代码上的操作

  1. 清除数据库级别的操作。
  2. 添加填充的字段,且在上面加入对应的注解。
//自动添加填充时间
@TableField(fill= FieldFill.INSERT)
private Date create_time;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date update_time;
  1. 编写一个对该注解处理的处理器类
package com.example.mybatisplus.handler;


import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill...");
        //处理创建和插入时的注解填充
        this.setFieldValByName("create_time",new Date(),metaObject);
        this.setFieldValByName("update_time",new Date(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill...");
        //处理更新时的注解填充
        this.setFieldValByName("update_time",new Date(),metaObject);
    }
}

7、乐观锁和悲观锁

乐观锁:对一些共享的资源但不会上锁,因为加了锁就会影响部分的性能,所以乐观锁不会加锁,它是使用CAS操作实现资源的安全。

悲观锁:不管什么情况都会加锁,加了锁就会影响性能,会设计锁的升级,升级成重量级时,即一个monitor

实现mysql数据库的乐观锁:

  • 取出记录时,获取当前的version版本
  • 更新时版本号加一
  • set version =newVersion where version=oldVersion
  • 如果版本号不对就更新失败

mysql数据库的乐观锁的实现

  1. 在数据库中加一个version的字段用来表示乐观锁。
ALTER TABLE plus ADD `version` INT(4) NOT NULL COMMENT '乐观锁'
  1. 在实体类中加上这个字段并且在该字段上加上乐观锁的注解 @Version。
//乐观锁
@Version
private Integer version;
  1. 注册组件,即注册乐观锁插件。
package com.example.mybatisplus.handler;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//扫描mapper包
@MapperScan("com.example.mybatisplus.dao")
//开启
@EnableTransactionManagement
@Configuration
public class MyVersionConfig {

    @Bean
    public MybatisPlusInterceptor myOptimisticLockerInnerInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;

    }
}
  1. 测试乐观锁
@Test
void contextLoads() {
    //先查询出乐观锁版本
    plus plus1=plusMapper.selectById(2);
    plus1.setName("hunan");
    //另一个线程插队执行
    plus plus2=plusMapper.selectById(2);
    plus2.setName("changsha");

    plusMapper.updateById(plus2);
    plusMapper.updateById(plus1);
    List<plus> pluses = plusMapper.selectList(null);
    pluses.forEach(System.out::println);
}

在这里插入图片描述

  • 先查询出来我们想要更新的记录用于获取乐观锁版本,然后就会根据乐观锁的版本来决定是否更新成功,当一个线程已经更新完成,另一个线程来的时候由于前一个线程将乐观锁的版本加1了,所以后来的的线程更新失败。

底层生成的SQL语句为:

update plus set name="changsha",version=version+1 where id=2 and version=1

注意:这里可能会遇到 **Mybatis_plus 出现 MP_OPTLOCK_VERSION_ORIGINAL ** 问题

解决办法参考网址:https://blog.csdn.net/heiiochange/article/details/114491848

8、分页查询

注册分页插件

package com.example.mybatisplus.handler;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//扫描mapper包
@MapperScan("com.example.mybatisplus.dao")
//开启
@EnableTransactionManagement
@Configuration
public class MyVersionConfig {
    
    @Bean
    //注册分页插件
    public PaginationInnerInterceptor getPaginationInnerInterceptor(){
        return new PaginationInnerInterceptor();
    }
}

测试

@Test
public void testPageLimit(){
    Page<plus> page = new Page<>(1,1);
    plusMapper.selectPage(page,null);
    page.getRecords().forEach(System.out::println);
}

9、逻辑删除

删除分为两种:

  • 物理删除:这是真正的删除,删除后在机器中就找不到了,永久删除了,就相当于将回收站中的东西清空。
  • 逻辑删除:这是逻辑上的删除,实际上还存在,就相当于将文件放到回收站中。

实现数据库的逻辑删除

  1. 数据库中加上一个表示逻辑删除的字段 (版本不同可能delete不能作为字段名,根据版本而定)

在这里插入图片描述

  1. 实体类中加上字段,并加上注解 @TableLogic
//逻辑删除
@TableLogic
private Integer delete;
  1. 配置config
@Bean
public ISqlInjector getISqlInjector(){
    return new LogicSqlInjector();
}

注意:在mybatis-plus 3.1.1版本之后的不需要配置了直接自动识别,只需 注解+.yaml

  1. 配置Application.yaml
mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1      #删除了为1
      logic-not-delete-value: 0  #没删除为0
  1. 测试
@Test
public void testLogic(){
    plusMapper.deleteById(2);
    List<plus> pluses = plusMapper.selectList(null);
    pluses.forEach(System.out::println);
}

在这里插入图片描述

在这里插入图片描述

  • 现在的删除方法走的其实是更新操作,就是将表示逻辑删除的字段修改一下值,后续的查询操作就查不出来该记录,因为已经逻辑删除了,但是在数据库中还是存在的,只不过有逻辑删除标记

10、条件构造器

mybatisplus中一些简单的SQL语句会自动帮我们生成但是一些复杂的SQL语句还是需要我们去约束一下,那么条件构造器就显得很重要了 Wrapper

  • Wrapper使用测试:
  @Test
    public void testWrapper1(){
        QueryWrapper<plus> wrapper = new QueryWrapper<>();
        //查出来的数据根据id排序
        wrapper.orderByDesc("id");
        List<plus> pluses = plusMapper.selectList(wrapper);
        pluses.forEach(System.out::println);
    }

    @Test
    public void testWrapper2(){
        QueryWrapper<plus> wrapper = new QueryWrapper<>();
        //查询名字不为空,密码不为空且收入大于10000的用户
       wrapper.isNotNull("name").isNotNull("password").ge("income",21);
        List<plus> pluses = plusMapper.selectList(wrapper);
        pluses.forEach(System.out::println);
    }

    @Test
    public void testWrapper3(){
        QueryWrapper<plus> wrapper = new QueryWrapper<>();
        //查询name值为qiumin的数据
        wrapper.eq("name","qiumin");
        List<plus> pluses = plusMapper.selectList(wrapper);
        pluses.forEach(System.out::println);
    }

    @Test
    public void testWrapper4(){
        QueryWrapper<plus> wrapper = new QueryWrapper<>();
        //查询说如在999到10000之间的银狐数据
       wrapper.between("income",999,10000);
        List<plus> pluses = plusMapper.selectList(wrapper);
        pluses.forEach(System.out::println);
    }

    @Test
    public void testWrapper5(){
        QueryWrapper<plus> wrapper = new QueryWrapper<>();
        //模糊查询  查询名字中不带 杰 的并且邮箱是以好结尾的用户数据
       wrapper.notLike("name","杰").likeLeft("mail","h");
        List<plus> pluses = plusMapper.selectList(wrapper);
        pluses.forEach(System.out::println);
    }

    @Test
    public void testWrapper6(){
        QueryWrapper<plus> wrapper = new QueryWrapper<>();
        //子查询
        wrapper.inSql("id","select id from user where id<6");
        List<plus> pluses = plusMapper.selectList(wrapper);
        pluses.forEach(System.out::println);
    }

参考mybatis-plus官网:

11、代码自动生成器

mybatis-plus可以自动的帮我们生成一张表的pojo、mapper、service、controller代码不需要我们手动的写,我们只需把表创建好,编写自动生成代码运行,程序就会自动的帮我们生成文件。包括swagger2

  • 导入包
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

<!--以下核心包-->
<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>
<!--代码生成需要用到的引擎-->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--以上核心包-->

<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
</dependencies>

  • 配置相关的环境、逻辑删除等等,代码生成在dev环境下才能生效
spring:
  profiles:
    active: dev
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis-plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1
      logic-not-delete-value: 0
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl


  • 代码自动生成程序

在test包下编写代码自动生成程序

package com.qiumin.mybatisplust;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
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;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;

public class qiuminCode {
    public static void main(String[] args) {
        //需要构建一个代码自动生成器对象
        AutoGenerator mpg = new AutoGenerator();

        //1、全局配置
        GlobalConfig gc = new GlobalConfig();  //注意导包正确
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("qiumin");   //设置作者
        gc.setOpen(false);
        gc.setFileOverride(false);
        gc.setServiceName("%sService"); //去Service的I前缀
        gc.setIdType(IdType.ID_WORKER);  //主键自增策略
        gc.setDateType(DateType.ONLY_DATE);   //时间类型
        gc.setSwagger2(true);  //接口文档
        mpg.setGlobalConfig(gc); //丢入自动生成器对象
        //2、设置数据源 [自己的数据源]
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis-plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc); //丢入自动生成器对象
        //3、包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("user");
        pc.setParent("com.qiumin");  //路径
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setXml("mapper.xml");
        pc.setController("controller");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        mpg.setPackageInfo(pc);  //丢入自动生成器对象
        //4、策略配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("user");  //设置要映射的表名
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setEntityLombokModel(true); //自动使用Lombok
        strategyConfig.setLogicDeleteFieldName("flag");   //逻辑删除
        //5、自动填充配置
        TableFill create_time = new TableFill("create_time", FieldFill.INSERT); //自动填充创建时间
        TableFill update_time = new TableFill("update_time", FieldFill.INSERT_UPDATE);  //自动填充更新时间
        ArrayList<TableFill> tableList = new ArrayList<>();
        tableList.add(create_time);
        tableList.add(update_time);
        strategyConfig.setTableFillList(tableList);
        strategyConfig.setVersionFieldName("version");  //乐观锁
        strategyConfig.setRestControllerStyle(true);

        mpg.setStrategy(strategyConfig);//丢入自动生成器对象
        mpg.execute(); //执行


    }
}

qiumin

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值