Mybatis-Plus
作者:mmseoamin日期:2024-01-19

一、简介

官方网站

Mybatis-Plus,第1张

 Mybatis-Plus,第2张

 

MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

Mybatis-Plus,第3张

 

二、特点

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

    三、安装

    • JDK 8+

    • Maven or Gradle

      
      
          com.baomidou
          mybatis-plus-boot-starter
          3.5.1
      

      引入 MyBatis-Plus 之后请不要再次引入 MyBatis 以及 MyBatis-Spring,以避免因版本差异导致的问题。

      四、代码生成器

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

      1、安装

      
          com.baomidou
          mybatis-plus-generator
          3.5.1
      
      
          org.freemarker
          freemarker
      

      当前包未传递依赖 MP 包,需要自己引入!

      适用版本:mybatis-plus-generator 3.5.1 及其以上版本,对历史版本不兼容!3.5.1 以下的请参考 代码生成器旧

      2、快速生成

      Mybatis-Plus,第4张

       3、代码修改

      package cn.kgc.mybatisplus;
      ​
      ​
      import com.baomidou.mybatisplus.annotation.IdType;
      import com.baomidou.mybatisplus.generator.FastAutoGenerator;
      import com.baomidou.mybatisplus.generator.config.OutputFile;
      import com.baomidou.mybatisplus.generator.config.rules.DateType;
      import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
      import com.zaxxer.hikari.util.SuspendResumeLock;
      ​
      import java.util.Collections;
      ​
      public class MyBatisPlusGeneratorV2{
          private static final String URL = "jdbc:mysql://localhost:3306/book";
          private static final String USERNAME = "root";
          private static final String PASSWORD = "root";
          private static final String AUTHOR = "cuiyi 
      cuiyi@zbitedu.cn";    private static final String OUT_PUT_DIR = System.getProperty("user.dir") + "/src/main/java";    private static final DateType DATE_TYPE = DateType.ONLY_DATE; // 使用java.util.date    private static final String PARENT_PACKAGE = "cn.kgc";    private static final String MODULE_NAME = "mybatisplus";    private static final String MAPPER_LOCATION = System.getProperty("user.dir") + "/src/main/resources/mappers";    private static final String TABLE_PREFIX = "t_";    private static final IdType IDTYPE = IdType.ASSIGN_ID; ​ ​    public static void main(String[] args) { ​        FastAutoGenerator               .create(URL,USERNAME,PASSWORD)               .globalConfig(builder -> {                    builder.author(AUTHOR) // 设置作者                            //.enableSwagger() // 开启 swagger 模式                           .fileOverride() // 覆盖已生成文件                           .outputDir(OUT_PUT_DIR)// 指定输出目录                           .disableOpenDir()                           .dateType(DATE_TYPE);               })               .packageConfig(builder -> {                    builder.parent(PARENT_PACKAGE) // 设置父包名                           .moduleName(MODULE_NAME) // 设置父包模块名                           .pathInfo(Collections.singletonMap(OutputFile.mapperXml,  MAPPER_LOCATION )); // 设置mapperXml生成路径 ​               })               .strategyConfig(builder -> {                    builder                           .addTablePrefix(TABLE_PREFIX)                           .entityBuilder()                               .enableLombok()                               .idType(IDTYPE)                           .controllerBuilder()                               .enableRestStyle()                           .serviceBuilder()                               .convertServiceFileName(entityName -> entityName+"Service")                   ; // 设置过滤表前缀 ​               })               .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板               .execute(); ​   } }

      完整配置项

      五、CURD接口

      1、Service层接口

      说明:

      • 通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆,

      • 泛型 T 为任意实体对象

      • 建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类

      • 对象 Wrapper 为 条件构造器,用于构造where条件

        1-1 Save

        // 插入一条记录(选择字段,策略插入)
        boolean save(T entity);
        // 插入(批量)
        boolean saveBatch(Collection entityList);
        // 插入(批量)
        boolean saveBatch(Collection entityList, int batchSize);

        1-2 SaveOrUpdate

        // TableId 注解的字段存在更新记录,否插入一条记录
        // 没有id或者有id但是数据库没有数据:save 
        boolean saveOrUpdate(T entity);
        // 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
        boolean saveOrUpdate(T entity, Wrapper updateWrapper);
        // 批量修改插入
        boolean saveOrUpdateBatch(Collection entityList);
        // 批量修改插入
        boolean saveOrUpdateBatch(Collection entityList, int batchSize);

        1-3 Remove

        // 根据 entity 条件,删除记录
        boolean remove(Wrapper queryWrapper);
        // 根据 ID 删除
        boolean removeById(Serializable id);
        // 根据 columnMap 条件,删除记录
        boolean removeByMap(Map columnMap);
        // 删除(根据ID 批量删除)
        boolean removeByIds(Collection idList);

        1-4 Update

        // 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
        boolean update(Wrapper updateWrapper);
        // 根据 whereWrapper 条件,更新记录
        boolean update(T updateEntity, Wrapper whereWrapper);
        // 根据 ID 选择修改  动态SQL
        boolean updateById(T entity);
        // 根据ID 批量更新
        boolean updateBatchById(Collection entityList);
        // 根据ID 批量更新
        boolean updateBatchById(Collection entityList, int batchSize);

        1-5 Get

        // 根据 ID 查询
        T getById(Serializable id);
        // 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
        T getOne(Wrapper queryWrapper);
        // 根据 Wrapper,查询一条记录
        T getOne(Wrapper queryWrapper, boolean throwEx);
        // 根据 Wrapper,查询一条记录
        Map getMap(Wrapper queryWrapper);
        // 根据 Wrapper,查询一条记录
         V getObj(Wrapper queryWrapper, Function mapper);

        1-6 List

        // 查询所有
        List list();
        // 查询列表
        List list(Wrapper queryWrapper);
        // 查询(根据ID 批量查询)
        Collection listByIds(Collection idList);
        // 查询(根据 columnMap 条件)
        Collection listByMap(Map columnMap);
        // 查询所有列表
        List> listMaps();
        // 查询列表
        List> listMaps(Wrapper queryWrapper);
        // 查询全部记录
        List listObjs();
        // 查询全部记录
         List listObjs(Function mapper);
        // 根据 Wrapper 条件,查询全部记录
        List listObjs(Wrapper queryWrapper);
        // 根据 Wrapper 条件,查询全部记录
         List listObjs(Wrapper queryWrapper, Function mapper); 
        

        1-7 Page

        先配置分页插件

        Mybatis-Plus,第5张

        API方法

         

        // 无条件分页查询
        IPage page(IPage page);
        // 条件分页查询
        IPage page(IPage page, Wrapper queryWrapper);
        // 无条件分页查询
        IPage> pageMaps(IPage page);
        // 条件分页查询
        IPage> pageMaps(IPage page, Wrapper queryWrapper);

        1-8 Count

        // 查询总记录数
        int count();
        // 根据 Wrapper 条件,查询总记录数
        int count(Wrapper queryWrapper);

        2、Mapper层接口

        • 通用 CRUD 封装BaseMapper接口,为 Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器

        • 泛型 T 为任意实体对象

        • 参数 Serializable 为任意类型主键 Mybatis-Plus 不推荐使用复合主键约定每一张表都有自己的唯一 id 主键

        • 对象 Wrapper 为 条件构造器

        • Service实现类中内置了

          • baseMapper 属性

          • getBeseMapper 方法

          2-1 Insert

          // 插入一条记录
          int insert(T entity);

          2-2 Delete

          int delete(@Param(Constants.WRAPPER) Wrapper wrapper);
          // 删除(根据ID 批量删除)
          int deleteBatchIds(@Param(Constants.COLLECTION) Collection idList);
          // 根据 ID 删除
          int deleteById(Serializable id);
          // 根据 columnMap 条件,删除记录
          int deleteByMap(@Param(Constants.COLUMN_MAP) Map columnMap);

          2-3 Update

          // 根据 whereWrapper 条件,更新记录
          int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper whereWrapper);
          // 根据 ID 修改
          int updateById(@Param(Constants.ENTITY) T entity);

          2-4 Select

          // 根据 ID 查询
          T selectById(Serializable id);
          // 根据 entity 条件,查询一条记录
          T selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper);
          ​
          // 查询(根据ID 批量查询)
          List selectBatchIds(@Param(Constants.COLLECTION) Collection idList);
          // 根据 entity 条件,查询全部记录
          List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper);
          // 查询(根据 columnMap 条件)
          List selectByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
          // 根据 Wrapper 条件,查询全部记录
          List> selectMaps(@Param(Constants.WRAPPER) Wrapper queryWrapper);
          // 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
          List selectObjs(@Param(Constants.WRAPPER) Wrapper queryWrapper);
          ​
          // 根据 entity 条件,查询全部记录(并翻页)
          IPage selectPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
          // 根据 Wrapper 条件,查询全部记录(并翻页)
          IPage> selectMapsPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
          // 根据 Wrapper 条件,查询总记录数
          Integer selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper); 
          

          2-5 自定义Mapper方法

          Mybatis-Plus,第6张

          Mybatis-Plus,第7张

          3、ActiveRecord 模式

          说明:

          • 实体类只需继承 Model 类即可进行强大的 CRUD 操作

          • 需要项目中已注入对应实体的BaseMapper

          class User extends Model{
              // fields...
          }
          User user = new User();
          user.insert();
          user.selectAll();
          user.updateById();
          user.deleteById();
          // ...

          六、条件构造器

          1、AbstractWrapper

          1-1 说明

          QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类 用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件 注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为

          1-2 常用方法

          allEq、eq、ne、gt、ge、lt、le、between、notBetween、like、notLike、likeLeft、likeRight、isNull、isNotNull、in、notIn、inSql、notInSql、groupBy、orderByAsc、orderByDesc、orderBy、having、func、or、and、nested、apply、last、exists、notExists

          2、实现类

          QueryWrapper :查询用Wrapper / LambdaQueryWrapper: Lambda方式构造Wrapper

          UpdateWrapper:修改用Wrapper / LambdaUpdateWrapper:Lambda方式构造Wrapper

          3、Wrapper创建方式

          以Query为例

          3-1 方式1

          QueryWrapper wrapper = new QueryWrapper<>(); 
          wrapper.eq("id",2);
          wrapper.like("url","https");
          QueryWrapper wrapper = Wrappers.query();
          wrapper.eq("id",2);
          wrapper.like("url","https");

          破环三层结构, 不要使用

          3-2 方式2

          Advs advs = new Advs();
          QueryWrapper wrapper = new QueryWrapper<>(advs); 
          Advs advs = new Advs();
          QueryWrapper wrapper = Wrappers.query(advs);

          使用对象构建查询条件。

          3-3 方式3

          使用LambdaQueryWrapper

          LambdaQueryWrapper wrapper = Wrappers
              .lambdaQuery(Advs.class)
              .eq(Advs::getUrl,"someUrl");
          Advs advs = new Advs();
          LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(advs)
              .eq(Advs::getUrl,advs.getUrl());
          LambdaQueryWrapper wrapper =new LambdaQueryWrapper<>();
          wrapper.eq(Advs::getUrl,"someUrl");

          Wrapper中所有的条件构建方法都可以多传入第一个参数,一个boolean类型参数,当值为true时,才在SQL中拼接该条件

          七、分页

          @Configuration
          public class MybatisPlusConfig {
              @Bean
              public MybatisPlusInterceptor mybatisPlusInterceptor() {
                  MybatisPlusInterceptor interceptor =  new MybatisPlusInterceptor();
                  interceptor.addInnerInterceptor(
                      new PaginationInnerInterceptor(DbType.MYSQL)
                  );
                  return interceptor;
              }
          }
          

          方式1

          @RequestMapping("/page")
          public R page(Page p){
              IPage page = productService.page(p);
              return R.success(page);
          }

          方式2

          @RequestMapping("/page")
          public R page(
              @RequestParam(value = "page",defaultValue = "1",
                            required = false)Integer curPage,
              @RequestParam(value = "rows",defaultValue = "4",
                            required = false)Integer rows
          ){
          //    Page p =  new Page(curPage,rows);
              Page p = Page.of(curPage,rows);
              IPage page = productService.page(p);
              return R.success(page);
          }

          方式3

          @Repository
          public interface ProductMapper extends BaseMapper {
              // 如果需要自定义查询+分页,
              //  只需要将Page对象作为Mapper接口方法的第一个参数传入即可
              Page selectFuzzy(Page p,@Param("pro") Product product);
          }

          注意: 其他普通参数,就需要添加@Param注解!

          如果认为 Page 对象不够,或者不满足 项目需求, 可以自己实现IPage接口/继承Page类, 重构Page对象

          八、主键生成策略

          Mybatis-Plus,第8张

           

          @Getter
          public enum IdType {
              /**
               * 数据库ID自增
               * 

          该类型请确保数据库设置了 ID自增 否则无效

              */    AUTO(0),    /**     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)     */    NONE(1),    /**     * 用户输入ID     *

          该类型可以通过自己注册自动填充插件进行填充

              */    INPUT(2), ​    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */    /**     * 分配ID (主键类型为number或string),     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)     *     * @since 3.3.0     */    ASSIGN_ID(3),    /**     * 分配UUID (主键类型为 string)     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))     */    ASSIGN_UUID(4); }

          九、扩展

          Mybatis-Plus,第9张

          十、企业高级特性

          Mybatis-Plus,第10张

          十一、插件

          1、总览

          Mybatis-Plus,第11张