2023MybatisPlus详细教程

154 阅读14分钟

一、🎄MybatisPlus概述

为什么要学习它呢 ? MyBatisplus可以节省我们大量工作时间,所有的CRUD代码它都可以自动化完成!

简介

官网:MyBatis-Plus

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

愿景

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

img

特性:

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

支持数据库

  • MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb,informix,TDengine,redshift
  • 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库,优炫数据库,星瑞格数据库

框架结构

framework

二、🎏快速使用

官方文档-快速开始 | MyBatis-Plus (baomidou.com)

本文使用的Mybatis-Plus版本为最新的3.5.3.2,SpringBoot版本为2.7.15

技能掌握前提:

  • 拥有 Java 开发环境以及相应 IDE
  • 熟悉 Spring Boot
  • 熟悉 Maven

步骤

  1. 创建数据库mybatis_plus

  2. 创建user表

    DROP TABLE IF EXISTS user;
    
    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)
    );
    --真实开发中version(乐观锁),deleted(逻辑删除),gmt_create,gmt_modif都是必要的字段,后面会添加上。
    --插入相关数据
    DELETE FROM user;
    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');
    
  3. 使用SpringBoot初始化项目

    image-20230902160316029

  4. 添加依赖

    <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <version>1.18.28</version>
    </dependency>
    
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.22</version>
    </dependency>
    
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.2</version>
    </dependency>
    

    提示:不要同时导入mybatis和mybatis-plus

  5. 连接数据库

    注意:Mysql5和Mysql8的配置不同,mysql8的url配置需要添加时区,这儿使用的是yaml格式进行配置,后面所有配置都将使用yaml

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
        username: root
        password: toor
        driver-class-name: com.mysql.cj.jdbc.Driver
    
  6. ==传统方式:pojo-dao ( 连接mybatis,配置mapper.xml文件 )-service-controller==

  7. 现在:

    1. 创建pojo

      package com.mybatisplus.pojo;
      
      import lombok.AllArgsConstructor;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      //注意,此处开启了链式编程
      @Accessors(chain = true)
      public class User {
          // 对应教据库中的主键(uuid、自id、雪化算、redis、zookeeper)
          private Long id;
          private String name;
          private Integer age;
          private String email;
      }
      
    2. 创建mapper接口

      package com.mybatisplus.mapper;
      
      import com.baomidou.mybatisplus.core.mapper.BaseMapper;
      import com.mybatisplus.pojo.User;
      import org.springframework.stereotype.Repository;
      
      @Repository
      public interface UserMapper extends BaseMapper<User> {
          //所有CRUD操作以及完成,不需要写SQL
      }
      
    3. 使用

      @SpringBootTest
      class MybatisPlusApplicationTests {
          //继承自BaseMapper,所有方法都来自父类,也可以编写自己的扩展方法
          @Resource
          private UserMapper userMapper;
      
          @Test
          void contextLoads() {
              //通过id查询用户
              System.out.println(userMapper.selectById(1));
              //查询全部用户,其参数是一个wrapper条件构造器,不需要则使用null
              userMapper.selectList(null).forEach(System.out::println);
          }
      }
      

      注意:需要在主启动类上使用MapperScan注解扫描所有mapper

    4. 运行效果

      image-20230903095600679

      CRUD的方法和SQL都由Mybatis-Plus帮我们编写完成

三、🎁配置日志

官方文档-日志配置 | MyBatis-Plus (baomidou.com)

配置日志的原因

我们现在所有的执行的SQL是不可见的,我们想要在开发过程中进行调试时,必须查看日志

#日志配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

效果:所有执行的SQL都被输出

image-20230903100537888

四、🎪CRUD扩展

插入操作

@Test
void testInsert() {
    User user = new User().setName("张三").setAge(12).setEmail("123@qq.com");
    int result = userMapper.insert(user);
    System.out.println(insert);
}

效果:

image-20230903102600277

数据库插入的id的默认值为:全局的唯一id

主键生成策略

官方文档-主键策略 | MyBatis-Plus (baomidou.com)

User类中的id对应数据库中的主键,其中常见数据库主键自增策略有,uuid、自增id、雪化算法,在这儿用到的自增策略便是==雪花算法==

雪花算法(SnowFlake)简介

该算法由Twitter公司发明,主要目的是==解决在分布式环境下ID的生成问题==。雪花算法生成的ID是一个64位的整数,由时间戳、机器标识和序列号组成。时间戳部分占据41位,可以使用69年;机器标识部分占据10位,最多可以在1024个节点(包括5位datacenterId和5位workerId)中部署;序列号部分占据12位,同一毫秒时间戳可以生成4096个不重复的ID。因此,雪花算法能够保证生成的ID是==唯一==且自增的。

datacenterId的意思为数据中心的id,比如有些服务器在北京,香港,伦敦

workerId的意思为机器id,标识生成ID的机器的10位数字

主键默认生成策略

mybatis-plus默认主键自增策略

自 3.3.0 开始,默认使用雪花算法+UUID(不含中划线)

image-20230903122821249

在User类中的id字段上添加注解==@TableId(type = IdType.ASSIGN_ID)==。

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
@Test
void testInsert() {
    User user = new User().setName("张三").setAge(12).setEmail("123@qq.com");
    int insert = userMapper.insert(user);
    System.out.println(insert);
}

image-20230903151015609

其它自增主键策略

主键自增

配置主键自增:

  1. 实体类上id字段加上注解==@TableId(type = IdType.AUTO)==

  2. 数据库字段也要设置自增长

    image-20230903123836493

  3. 实现效果

    image-20230903150109599

    image-20230903150419618

其余自增效果的源码解释

//
// 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),//分配id
    ASSIGN_UUID(4);//分配uuid

    private final int key;

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

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

实体类上id字段加上注解==@TableId(type = IdType.INPUT)==

执行插入测试

@Test
void testInsert() {
    User user = new User()
            .setName("张三")
            .setAge(12)
            .setEmail("123@qq.com");
    userMapper.insert(user);
}

image-20230903151422989

更新操作

@Test
void testUpdate() {
    User user = new User()
        //通过条件自动拼接动态SQL
        .setId(1L)
        .setName("王五")
        .setAge(8)
        .setEmail("456@gmail.com");
    //注意updateById,其传入的参数是一个对象
    int update = userMapper.updateById(user);
    System.out.println(update);
}

image-20230903152116450

所有SQL都是自动配置

自动填充

官方文档-自动填充 | MyBatis-Plus (baomidou.com)

创建时间,修改时间,这些操作都是自动化完成,我们不希望手动更新

阿里巴巴开发手册:必备的三个字段id, gmt_create, gmt_modified。

image-20230903154626873

方式一:数据库级别(不建议)

  1. 在数据库中新增字段,create_time和update_time

    image-20230903155918903

  2. 再次测试插入方法,需要现在实体类同步

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    public class User {
        // 对应教据库中的主键(uuid、自id、雪化算、redis、zookeeper)
        @TableId(type = IdType.ASSIGN_ID)
        private Long id;
        private String name;
        private Integer age;
        private String email;
        //新增的字段
        private Date createTime;
        private Date updateTime;
    }
    
    @Test
    void testInsert() {
        User user = new User()
            .setName("张三")
            .setAge(12)
            .setEmail("123@qq.com");
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }
    

    image-20230903160119159

  3. 再次更新

    @Test
    void testUpdate() {
        User user = new User()
            .setId(1698244309027500034L)
            .setName("王五")
            .setAge(8)
            .setEmail("456@gmail.com");
        int update = userMapper.updateById(user);
        System.out.println(update);
    }
    }
    

    image-20230903160534340

方式二:代码级别

  1. 去掉所有数据库中create_time和update_time字段的默认值

    image-20230903160750884

  2. 在实体类上的相关字段上添加注解@TableField

    //字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    
  3. 编写处理器来处理这个注解

    package com.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.time.LocalDateTime;
    import java.util.Date;
    
    @Slf4j
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
        //插入时的填充策略
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("插入");
            //setFieldValByName(String fieldName, Object fieldVal, MetaObject)
            this.setFieldValByName("createTime", new Date(), metaObject);
            this.setFieldValByName("updateTime", new Date(), metaObject);
    //        this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
    //        this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
        }
    
        //更新时的填充策略
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("更新");
            this.setFieldValByName("updateTime", new Date(), metaObject);
    //        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
        }
    }
    
    

    注意:该段代码中注释了另外一种写法,这是mybatis-plus 3.3.0+版本过后官方推荐的写法,但是不管怎样的写法,都要注意数据类型的一致,使用LocalDateTime的话,实体类的两个字段就要改成LocalDateTime

  4. 执行插入操作

    @Test
    void testInsert() {
        User user = new User()
            .setName("张三")
            .setAge(12)
            .setEmail("123@qq.com");
        userMapper.insert(user);
    }
    

    image-20230903185627045

  5. 再执行更新操作

    @Test
    void testUpdate() {
        User user = new User()
            .setId(1698244309027500042L)
            .setName("王五")
            .setAge(8)
            .setEmail("456@gmail.com");
        int update = userMapper.updateById(user);
        System.out.println(update);
    }
    

    image-20230903185855679

乐观锁(Optimistic Locking)

官方文档-乐观锁插件 | MyBatis-Plus (baomidou.com)

乐观锁是一种并发控制机制,它持有乐观的态度,相信数据冲突发生的概率较低,并允许多个任务并行地对数据进行操作,而不加锁。乐观锁的机制下,对数据的操作不会立即进行冲突检测和加锁,而是在数据提交时通过一种机制来验证是否存在冲突。乐观锁通常==通过版本号(也称为时间戳)实现==。每次读取数据时,都会获取当前版本号,并将其与修改前的版本号进行比对。如果两个版本号相同,则认为数据没有被其他任务修改,允许当前任务进行修改操作并更新版本号。如果版本号不同,则表示数据已被其他任务修改,此时需要处理冲突,通常是通过回滚操作或者给出适当的提示来解决冲突。

乐观锁:顾名思义十分乐观,它总是认为任务==不会==出现问题,无论干什么都不会上锁,如果出现问题,再次更新值测试

悲观锁:顾名思义十分悲观,它总是任务任务==总会==出现问题,无论干什么都上锁,再去操作

乐观锁实现方式:

  • 取出记录时,获取当前 version
  • 更新时,带上这个 version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果 version 不对,就更新失败
乐观锁:先查询,获得版本号version=1
--A线程
update user set name = "张三", verison = version+1
where id = 2 and version = 1

--B线程 线程抢先完成,这个时候version = 2,会导致A修改失败!
update user set name = "张三", version = version + 1
where id = 2 and version = 1

测试Mybatis-Plus乐观锁插件

  1. 给数据库增加verison字段,将其==默认值设置为1==

    image-20230904191025987

  2. User实体类添加相应的字段

    @Version//这是一个乐观锁
    private Integer version;
    
  3. 配置拦截器组件

    package com.mybatisplus.config;
    
    @Configuration
    @EnableTransactionManagement
    @MapperScan("com.mybatisplus.mapper") //可以将主启动类扫描mapper放到这儿
    public class MPConfig {
        /**
         * 新版写法
         * */
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return interceptor;
        }
        /**
         * 旧版写法
         */
    //    @Bean
    //    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    //        return new OptimisticLockerInterceptor();
    //    }
    
    }
    
  4. 测试乐观锁==成功案例==

    //测试乐观锁成功案例
    @Test
    void testOptimisticLockSuccess() {
        //查询用户信息
        User user = userMapper.selectById(1L);
        //修改用户信息
        user.setAge(34).setName("丙丁");
        userMapper.updateById(user);
    }
    

    image-20230904201930913

  5. 测试乐观锁==失败案例==

    //测试乐观锁失败案例
    @Test
    void testOptimisticLockFail() {
        //模拟线程1
        User user = userMapper.selectById(1L);
        user.setAge(34).setName("丙丁11111");
    
    
        //模拟另外一个线程执行插队操作
        User user2 = userMapper.selectById(1L);
        user2.setAge(34).setName("丙丁22222");
    
        userMapper.updateById(user2);
        userMapper.updateById(user);//如果没有乐观锁,就会覆盖插队线程的值
    }
    

    image-20230904213156632

    image-20230904213253861

查询操作

  1. 查询单个用户

    //测试通过id查询用户
    @Test
    void testSelectById() {
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }
    

    image-20230905134153582

  2. 批量查询多个用户

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

    image-20230905135001392

  3. 条件查询map

    //测试使用map进行条件查询
    @Test
    void testSelectByMaps() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "丙丁22222");
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }
    

    image-20230905171503626

    提示:如果map中有多个字段,mybatis-plus会使用and去拼接

    image-20230905175144673

分页查询

官方文档-分页插件 | MyBatis-Plus (baomidou.com)

几种常见的分页方式:

  1. 在SQL语句中使用limit语句
  2. pageHelper第三方插件
  3. MP内置的分页插件

如何使用

  1. 配置拦截器组件

    @Configuration
    @EnableTransactionManagement
    @MapperScan("com.mybatisplus.mapper")
    public class MPConfig {
        /**
         * 新版写法
         * */
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            //乐观锁插件
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            //分页插件
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            return interceptor;
        }
    
    }
    
  2. 直接使用Page对象

    //测试分页查询
    @Test
    void testPage() {
        //第一个参数:当前页
        //第二个参数:页面的大小
        Page<User> page = new Page<>(1,3);
        Page<User> userPage = userMapper.selectPage(page, null);
        userPage.getRecords().forEach(System.out::println);
    }
    

    image-20230905212443887

删除操作

  1. 通过id删除

    //测试通过id删除
    @Test
    void testDelete() {
        userMapper.deleteById(1698244309027500042L);
    }
    

    image-20230905212952786

  2. 批量删除

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

    image-20230905213200991

  3. 条件删除

    //测试条件删除
    @Test
    void testDeleteByMap() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "小黎");
        userMapper.deleteByMap(map);        
    }    
    

    image-20230905213856600

逻辑删除

官方文档-逻辑删除 | MyBatis-Plus (baomidou.com)

物理删除(硬删除):从数据库中直接删除数据

逻辑删除(软删除):在数据库中没有被删除,而是通过设置一个字段将其失效,比如一个deleted字段,为0时就是未被删除,为1就是被删除,然后在查询数据时带上deleted字段作条件查询

有些网站有管理员可以查看被删除记录的功能,它的作用就是防止数据丢失,类似于回收站

  1. 在数据库中增加一个deleted字段

    image-20230905215650660

  2. 实体类中增加属性

    @TableLogic//逻辑删除
    private Integer deleted;
    
  3. 编写配置文件

    #日志配置
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      #逻辑删除相关配置
      global-config:
        db-config:
          logic-delete-field: deleted #全局逻辑删除的实体字段名(从3.3.0+版本过后可以不用加@TableLogic注解)
          logic-delete-value: 1 #逻辑已删除值(默认为1)
          logic-not-delete-value: 0 #逻辑未删除值(默认为0)
    

提示:如果你用的MP版本是3.3.0+的,就不用在实体类上加@TableLogic注解

  1. 测试删除

    @Test
    void testLogicDelete() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "小王");
        //先对数据进行逻辑删除
        userMapper.deleteByMap(map);
        //再查询删除的数据
        userMapper.selectByMap(map).forEach(System.out::println);
    }
    

    数据库中依然存在被逻辑删除的数据,但是最后的deleted字段变成了1

    image-20230905221339365

    先删后查,查询时携带了deleted=0的条件,没有查询到数据自动的过滤掉了被逻辑删除的数据,其本质就是更新操作

    image-20230905221314658

五、🥗性能分析插件

在日常的开发中,会有一个慢SQL而我们可以使用一些分析插件进行分析

提示:MP 3.2+版已经将内置的性能分析插件移除,需要自己使用第三方的性能分析插件

此处使用p6spy

  1. 导入依赖

    <dependency>  
       <groupId>p6spy</groupId>  
       <artifactId>p6spy</artifactId>  
       <version>3.9.1</version>  
    </dependency>
    
  2. 替换MySQL8驱动

    spring:
      datasource:
      	#注意此处加了一个p6spy
        url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus? characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
        username: root
        password: xxxx #密码换成自己的
        driver-class-name: com.p6spy.engine.spy.P6SpyDriver #换驱动
    
  3. 在resources目录下新建spy.propertis文件

    modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
    logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
    #日志输出到控制台
    appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
    # 使用日志系统记录 sql
    # 设置 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=1
    
  4. 测试查询全部用户

    @Test
    void contextLoads() {
        userMapper.selectList(null).forEach(System.out::println);
    }
    
  5. 效果,打印出了SQL的执行时间

    image-20230906093704608

六、🥩条件查询器(Wrapper)

官方文档-条件构造器 | MyBatis-Plus (baomidou.com)

复杂的SQL可以用它替代

  1. 查询name不为空,email不为空的用户,且age大于等于23的

    @Test
    void test1() {
        //查询name不为空,email不为空的用户,且age大于等于23的
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name").isNotNull("email").ge("age",23);
        userMapper.selectList(wrapper);
    }
    

    image-20230906140306654

  2. 通过名字查询用户,比如张三

    @Test
    void test2() {
        //通过名字查询用户,比如张三
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","张三");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }
    

    image-20230906141059170

  3. 查询年龄在15至30之间的人的数量

    @Test
    void test3() {
        //查询年龄在15至30之间的人的数量
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",15,30);//区间
        Long l = userMapper.selectCount(wrapper);
        System.out.println(l);
    }
    

    image-20230906142104298

  4. 模糊查询

    @Test
    void test4() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //name字段中不包含k,email字段左模糊查询qq.com
        wrapper.notLike("name","k").likeLeft("email","qq.com");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }
    

    MP执行的SQL为

    SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE deleted=0 AND (name NOT LIKE '%k%' AND email LIKE '%qq.com')
    

    image-20230906144234814

  5. 嵌套查询

    //嵌套查询
    @Test
    void test5(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //id在子查询中查出
        wrapper.inSql("id","select id from user");
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);
    }
    
    SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE deleted=0 AND (id IN (select id from user))
    

    image-20230906150049289

  6. 降序查询

    //排序查询
    @Test
    void test6(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);
    }
    

    image-20230906150351022

七、🌮代码生成器

官方文档-代码生成器(新) | MyBatis-Plus (baomidou.com)

本人平常并未使用官方的代码生成工具而是使用的代码生成插件EasyCode

image-20230907100017711