【MybatisPlus快速入门】—— 进阶入门

进阶篇

1.1 映射专题

  • Mybatis 框架之所以能够简化数据库操作,是因为他内部的映射机制,通过自动映射,进行数据的封装,我们只要符合映射规则,就可以快速高效的完成SQL操作的实现
  • 既然 MybatisPlus 是基于Mybatis 的增强工具,所以也具有这样的映射规则

1.1.1 自动映射

  • 表名和实体类名映射 -> 表名user 实体类名User 【类名首字母小写后和表名相同】
  • 字段名和实体类属性名映射 -> 字段名name 实体类属性名name 【字段名和属性名相同】
  • 字段名下划线命名方式和实体类属性小驼峰命名方式映射 -> 字段名 user_email 实体类属性名 userEmail
    • MybatisPlus 支持这种映射规则,可以通过配置来设置 【在SpringBoot核心配置文件进行配置】
    map-underscore-to-camel-case: true 表示支持下划线到驼峰的映射
    map-underscore-to-camel-case: false 表示不支持下划线到驼峰的映射
    

1.1.2 表映射

  • 如果我们的表名和实体类名不一致怎么办?
    • 通过 @TableName() 注解指定映射的数据库表名,就会按照指定的表名进行映射

    • 如:此时将数据库的表名改为powershop_user,要完成表名和实体类名的映射,需要将实体类名也要指定为 powershop_user

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName("powershop_user")
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  • 如果有很多实体类,对应到数据库中的很多表,我们不需要每个依次配置,只需要配置一个全局的设置,他都会给每个实体类名前面添加指定的前缀,这里我们演示一下全局配置的效果
mybatis-plus:
  global-config:
    db-config:
      table-prefix: powershop_

1.1.3 字段映射

  • 表映射说明了表名与实体类名不一致的解决方法,那么什么场景下会改变字段映射呢?

  • 当数据库字段和表实体类的属性不一致时,我们可以使用 @TableField() 注解改变字段和属性的映射,让注解中的名称和表字段保持一致

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @TableField("username")
        private String name;
    }
    
  • 数据库字段和表实体类的属性一致,但是字段名为关键字,不能直接用于sql查询

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @TableField("`desc`")
        private String desc;
    }
    

1.1.4 字段失效

  • 当数据库中有字段不希望被查询,我们可以通过@TableField(select = false)来隐藏这个字段,那在拼接SQL语句的时候,就不会拼接这个字段
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @TableField(select = false)
        private Integer age;
    }
    

【MybatisPlus快速入门】—— 进阶入门_第1张图片

1.1.5 视图属性

  • 在实际开发中,有些字段不需要数据库存储,但是却需要展示,需要展示也就是意味着实体类中需要存在这个字段,我们称这些实体类中存在但是数据库中不存在的字段,叫做视图字段

  • 根据之前的经验,框架会默认将实体类中的属性作为查询字段进行拼接,那我们来思考,像这种视图字段,能够作为查询条件么,显示是不能的。因为数据库中没有这个字段,所以查询字段如果包含这个字段,SQL语句会出现问题

  • 我们通过 @TableField(exist = false) 来去掉这个字段,不让他作为查询字段

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @TableField(exist = false)
        private Integer online;
    }
    

【MybatisPlus快速入门】—— 进阶入门_第2张图片

1.2 条件构造器

  • 什么是条件构造器?
    • 条件构造器(Wrapper)是MyBatisPlus框架提供的一种方便的查询构建器,用于构建复杂的查询条件。
    • 它是基于Lambda表达式的,可以使用面向对象的方式构建查询条件,不需要写复杂的SQL语句,大大简化了数据库操作代码的编写。

1️⃣ 条件构造器图谱

2️⃣ 展开介绍

  • Wrapper 抽象类,条件类的顶层,提供了一些获取和判断相关的方法
  • AbstractWrapper 抽象类,Wrapper的子类,提供了所有的条件相关方法
  • AbstractLambdaWrapper 抽象类,AbstractWrapper的子类,确定字段参数为方法引用类型
  • QueryWrapper 类,AbstractWrapper的子类,如果我们需要传递String类型的字段信息,创建该对象
  • LambdaQueryWrapper 类,AbstractLambdaWrapper的子类,如果我们需要传递方法引用方式的字段信息,创建该对象

3️⃣ 我们在编写代码的时候,只需要关注QueryWrapper和LambdaQueryWrapper

1.3 查询专题

1.3.1 等值查询

1️⃣ eq 等值查询

(1)使用QueryWrapper对象,构建查询条件

@Test
    void eq() {
        //创建我们QueryWrapper对象 [创建条件查询对象]
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        //添加我们的查询条件 [此处演示的是等值查询] [设置查询条件,指定查询字段和匹配的值]
        userQueryWrapper.eq("name", "Jack");
        //调用我们的接口对象的方法 [进行条件查询]
        User user = userMapper.selectOne(userQueryWrapper);
        System.out.println(user);
    }

【MybatisPlus快速入门】—— 进阶入门_第3张图片

(2)使用 LambdaQueryWrapper 对象,构建查询条件

  • 在构建字段时,使用方法引用的方式来选择字段,这样做可以避免字段拼写错误出现问题
@Test
    void eq2() {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getName, "Jack");
        User user = userMapper.selectOne(userLambdaQueryWrapper);
        System.out.println(user);
    }

【MybatisPlus快速入门】—— 进阶入门_第4张图片

  • 还要考虑一种情况,我们构建的条件是从哪里来的?

    • 应该是从客户端通过请求发送过来的,由服务端接收的。
    • 在网站中一般都会有多个条件入口,用户可以选择一个或多个条件进行查询,那这个时候在请求时,我们不能确定所有的条件都是有值的,部分条件可能用户没有传值,那该条件就为null。
      • 比如在电商网站中,可以选择多个查询条件
  • 那为null的条件,我们是不需要进行查询条件拼接的,否则就会出现如下情况,将为null的条件进行拼接,筛选后无法查询出结果

@Test
    void isNull() {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getName, null);
        User user = userMapper.selectOne(userLambdaQueryWrapper);
        System.out.println(user);
    }

【MybatisPlus快速入门】—— 进阶入门_第5张图片

  • 当然我们要解决这个问题,可以先判断是否为空,根据判断结果选择是否拼接该字段,这个功能其实不需要我们写,由MybatisPlus的方法已经提供好了。

请添加图片描述

@Test
    void isNull2() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String name = null;
        lambdaQueryWrapper.eq(name != null, User::getName, name);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第6张图片

2️⃣ allEq

(1)先演示一下如何通过多个eq,构建多条件查询【这部分也可以采用链式调用】

@Test
    void allEq1() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getName, "Tom");
        lambdaQueryWrapper.eq(User::getAge, 28);
        User user = userMapper.selectOne(lambdaQueryWrapper);
        System.out.println(user);
    }

【MybatisPlus快速入门】—— 进阶入门_第7张图片

(2)如果此时有多个条件需要同时判断,我们可以将这多个条件放入到Map集合中,更加的方便

@Test
    void allEq2() {
        //创建一个集合来保存我们的多个查询条件
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("name", "Tom");
        //此处测试修改参数值为null
        hashMap.put("age", null);
        //此时不能使用我们的LambdaQueryWrapper了,只能用QueryWrapper
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.allEq(hashMap, true);
        User user = userMapper.selectOne(queryWrapper);
        System.out.println(user);
    }
  • allEq(Map params, boolean null2IsNull)

    • 参数params:表示传递的Map集合
    • 参数null2IsNull:表示对于为null的条件是否判断isNull
  • 第二个参数设置为 false 的效果就是如果字段值为空,那么就不会拼接为查询条件
    【MybatisPlus快速入门】—— 进阶入门_第8张图片

3️⃣ ne 不等查询

@Test
    void ne() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.ne(User::getName, "Tom");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第9张图片

1.3.2 范围查询

1️⃣ gt 大于

@Test
    void gt() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.gt(User::getAge, 19);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第10张图片

2️⃣ ge 大于等于

@Test
    void ge() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.ge(User::getAge, 18);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第11张图片

3️⃣ lt 小于

@Test
    void lt() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.lt(User::getAge, 19);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第12张图片

4️⃣ le 小于等于

@Test
    void le() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.le(User::getAge, 20);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第13张图片

5️⃣ between 在范围内 【包括端点值】

@Test
    void between() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.between(User::getAge, 18, 21);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第14张图片

6️⃣ notBetween 不在范围内

@Test
    void notBetween() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.notBetween(User::getAge, 18, 21);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第15张图片

1.3.3 模糊查询

1️⃣ like 模糊查询

@Test
    void like() {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.like(User::getName, "j");//全模糊匹配,只要包含J
        List<User> users = userMapper.selectList(userLambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第16张图片

2️⃣ notLike 模糊查询

@Test
    void notLike() {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.notLike(User::getName, "j");//全模糊匹配,只要包含J
        List<User> users = userMapper.selectList(userLambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第17张图片

3️⃣ likeLeft 模糊查询 【以XXX结尾】

@Test
    void likeLeft() {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.likeLeft(User::getName, "e");//以XX结尾
        List<User> users = userMapper.selectList(userLambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第18张图片

4️⃣ likeRight 模糊查询【以XXX开头】

@Test
    void likeRight() {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.likeRight(User::getName, "J");//以XX开头
        List<User> users = userMapper.selectList(userLambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第19张图片

1.3.4 判空查询

1️⃣ isNull 是否为空

@Test
    void isNull3() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.isNull(User::getName);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第20张图片

2️⃣ isNotNull 是否不为空

@Test
    void isNotNull() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.isNotNull(User::getName);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第21张图片

1.3.5 包含查询

1️⃣ in 包含在范围内 【也可以用or实现】

@Test
    void in() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        ArrayList<Integer> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, 18, 20, 21);
        lambdaQueryWrapper.in(User::getAge, arrayList);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第22张图片

2️⃣ notIn 不包含在范围内

@Test
    void notIn() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        ArrayList<Integer> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, 18, 20, 21);
        lambdaQueryWrapper.notIn(User::getAge, arrayList);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第23张图片

3️⃣ inSql 包含在范围内(自己拼接SQL的形式)

  • 通过自己拼接SQL的方式来完成包含查询
    • 字节写个字符串充当集合,多个元素用逗号分隔开
    • 也可以通过 inSql 实现嵌套查询,将一个查询结果作为另一个查询条件
@Test
    void inSql() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.inSql(User::getAge, "18, 20, 22");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第24张图片

@Test
    void inSql2() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.inSql(User::getAge, "select age from user where age > 20");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第25张图片

4️⃣ notInSql 不包含在范围内(自己拼接SQL的形式)

@Test
    void notInSql() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.notInSql(User::getAge, "18, 20, 22");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第26张图片

@Test
    void notInSql2() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.notInSql(User::getAge, "select age from user where age > 20");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第27张图片

1.3.6 分组查询

1️⃣ groupBy 按指定字段分组

@Test
    void groupBy() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //分组字段,我们通过groupBy方法指定按哪个字段分组
        queryWrapper.groupBy("age");
        //查询字段,我们要查询出来哪些数据
        queryWrapper.select("age", "count(*) as field_count");
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        System.out.println(maps);
    }

【MybatisPlus快速入门】—— 进阶入门_第28张图片

1.3.7 聚合查询

  • 在分组查询的基础上,通过 having 来实现聚合查询
    请添加图片描述
@Test
    void having() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //分组字段
        queryWrapper.groupBy("age");
        //查询字段
        queryWrapper.select("age", "count(*) as field_count");
        //聚合筛选
        queryWrapper.having("field_count >= 2");
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        System.out.println(maps);
    }

【MybatisPlus快速入门】—— 进阶入门_第29张图片

1.3.8 排序查询

1️⃣ orderByAsc 升序查询

@Test
    void orderByAsc() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.orderByAsc(User::getAge, User::getId);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第30张图片

2️⃣ orderByDesc 降序查询

@Test
    void orderByDesc() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.orderByDesc(User::getAge, User::getId);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第31张图片

3️⃣ orderBy 可同时指定升序降序查询

  • 自己定制实现根据某些字段做升序、某些字段做降序排序
    • 多次调用 orderBy 方法
    • 第一个参数代表 如果字段值为空,是否还参与排序
    • 第二个参数代表 是否为升序排序
    • 第三个参数代表 我们选择排序的字段
@Test
    void orderBy(){
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.orderBy(false, true, User::getAge);
        userLambdaQueryWrapper.orderBy(true, false, User::getId);
        List<User> users = userMapper.selectList(userLambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第32张图片

  • 有一个需要注意的地方:说明我们将orderBy的第一个条件设置为 false,那么只要查询范围内有一条数据的age为空,那么就会导致 age 这个字段不参与排序

【MybatisPlus快速入门】—— 进阶入门_第33张图片

1.3.9 func查询

  • 根据不同的业务情况来封装查询条件:【此处为了演示效果直接指定了boolean的类型】
    • 就是不同条件下我们的查询内容是不同的

1️⃣ 使用匿名内部类的形式 【可以简化为 Lambda 表达式的形式】

【MybatisPlus快速入门】—— 进阶入门_第34张图片
【MybatisPlus快速入门】—— 进阶入门_第35张图片
2️⃣ 下面为简化为Lambda表达式的形式

  • 在上面的代码按 Alt + Enter 就会提示我们进行转换

【MybatisPlus快速入门】—— 进阶入门_第36张图片

@Test
    void func(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.func(userLambdaQueryWrapper -> {
            if(true){
                lambdaQueryWrapper.eq(User::getId, 1);
            }else {
                lambdaQueryWrapper.ne(User::getId, 1);
            }
        });
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }
  • 引申知识点:
    • 什么情况下, Java匿名内部类可以简化为Lambda表达式形式
      【MybatisPlus快速入门】—— 进阶入门_第37张图片
    • 接口中的方法不都是抽象方法吗?
      【MybatisPlus快速入门】—— 进阶入门_第38张图片

1.3.10 逻辑查询

1️⃣ and 与查询

  • 我们通过链式调用,默认就是与查询
@Test
    void and(){
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.gt(User::getAge, 18).lt(User::getAge, 22);
        List<User> users = userMapper.selectList(userLambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第39张图片

  • 也可以采用嵌套的方式实现与查询
    【MybatisPlus快速入门】—— 进阶入门_第40张图片
@Test
    void and2(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getName, "jack").and(i -> i.gt(User::getAge, 26).or().lt(User::getAge, 22));
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第41张图片

2️⃣ or 或查询

  • 链式查询直接点调用 or() 代表或查询
@Test
    void or(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.lt(User::getAge, 20).or().gt(User::getAge, 22);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第42张图片

  • 当然我们的或查询也支持嵌套调用
    • 我们需要注意,是先完成内部查询再完成外部查询(先满足最内层的查询条件进行筛选)
@Test
    void or2(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getName, "Jack").or(i -> i.gt(User::getAge, 22).lt(User::getAge, 26));
        //IDEA中通过 Ctrl + Alt + V 可以快速生成变量名
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第43张图片

3️⃣ nested 快速构建查询

【MybatisPlus快速入门】—— 进阶入门_第44张图片

@Test
    void nested(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.nested(i -> i.eq(User::getName, "Tom").gt(User::getAge, 18));
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第45张图片

1.3.11 自定义条件查询

  • 通过 apply 方法可以实现自定义查询
@Test
    void apply(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //会将这部分的内容拼接到SQL的where后面
        lambdaQueryWrapper.apply("id = 1");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第46张图片

1.3.12 last查询

  • 通过last查询可以将我们指定的查询条件拼接到我们sql语句的最后【可以实现简单的分页查询】
@Test
    void last(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //limit用于分页,两个参数代表从第几条开始获得几条数据
        lambdaQueryWrapper.last("limit 0, 2");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第47张图片

1.3.13 exists查询

1️⃣ exists 存在查询

  • 就是根据子查询语句的结果来选择主查询的结果是否保留
@Test
    void exists(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.exists("select id from user where age = 18");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第48张图片

2️⃣ notExists 不存在查询

  • notExists 的作用是子查询有数据–主查询不保留,子查询没数据–主查询保留
@Test
    void notExists(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.notExists("select id from user where age = 18");
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第49张图片

1.3.14 字段查询

  • 通过 select 方法指定我们要查询哪些字段
@Test
    void select(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(User::getId, User::getName);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        System.out.println(users);
    }

【MybatisPlus快速入门】—— 进阶入门_第50张图片


高阶篇

2.1 主键策略

2.1.1 主键生成策略介绍

  • 首先大家先要知道什么是主键,主键的作用就是唯一标识,我们可以通过这个唯一标识来定位到这条数据。
  • 当然对于表数据中的主键,我们可以自己设计生成规则,生成主键。
  • 在MybatisPlus中提供了一个注解 @TableId,该注解提供了各种的主键生成策略,我们可以通过使用该注解来对于新增的数据指定主键生成策略
  • 那么在以后新增数据的时候,数据就会按照我们指定的主键生成策略来生成对应的主键。

2.1.2 AUTO策略

  • 该策略为跟随数据库表的主键递增策略,前提是数据库表的主键要设置为自增

【MybatisPlus快速入门】—— 进阶入门_第51张图片

  • 实体类添加注解,指定主键生成策略

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @TableId(type = IdType.AUTO)
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  • 测试程序:

    @Test
    void primaryKey(){
        User user = new User();
        user.setName("Mary");
        user.setAge(35);
        user.setEmail("[email protected]");
        userMapper.insert(user);
    }
    
  • 拼接的SQL语句如下
    在这里插入图片描述

2.1.3 INPUT策略

  • 该策略表示,必须由我们手动的插入id,否则无法添加数据

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @TableId(type = IdType.INPUT)
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  • 由于我们不使用AUTO了,所以把自动递增去掉

  • 这里如果我们省略不写id,会发现,无法插入数据

    @Test
    void primaryKey(){
        User user = new User();
        user.setName("Jerry");
        user.setAge(38);
        user.setEmail("[email protected]");
        userMapper.insert(user);
    }
    

【MybatisPlus快速入门】—— 进阶入门_第52张图片

  • 但是我们自己指定了id,发现可以添加成功
    @Test
    void primaryKey(){
        User user = new User();
        user.setId(8L);
        user.setName("Jerry");
        user.setAge(38);
        user.setEmail("[email protected]");
        userMapper.insert(user);
    }
    

2.1.4 ASSIGN_ID策略

  • 如果我们将来一张表的数据量很大,我们需要进行分表。

  • 常见的分表策略有两种:

    • 水平拆分: 就是将一个大的表按照数据量进行拆分
      【MybatisPlus快速入门】—— 进阶入门_第53张图片

    • 垂直拆分: 垂直拆分就是将一个大的表按照字段进行拆分
      【MybatisPlus快速入门】—— 进阶入门_第54张图片

  • 其实我们对于拆分后的数据,有三点需求,就拿水平拆分来说:

    • 之前的表的主键是有序的,拆分后还是有序的
    • 虽然做了表的拆分,但是每条数据还需要保证主键的唯一性
    • 主键最好不要直接暴露数据的数量,这样容易被外界知道关键信息
  • 那就需要有一种算法,能够实现这三个需求,这个算法就是雪花算法

  • 雪花算法是由一个64位的二进制组成的,最终就是一个Long类型的数值, 主要分为四部分存储【转为十进制是19位】

    • 1位的符号位,固定值为0
    • 41位的时间戳
    • 10位的机器码,包含5位机器id和5位服务id
    • 12位的序列号

【MybatisPlus快速入门】—— 进阶入门_第55张图片

  • 使用雪花算法可以实现有序、唯一、且不直接暴露排序的数字
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
@Test
void primaryKey(){
    User user = new User();
    user.setName("Jerry");
    user.setAge(38);
    user.setEmail("[email protected]");
    userMapper.insert(user);
}

我们可以在插入后发现一个19位长度的id,该id就是雪花算法生成的id,这是二级制的十进制表示形式
【MybatisPlus快速入门】—— 进阶入门_第56张图片

2.1.5 NONE策略

  • NONE策略表示不指定主键生成策略,当我们没有指定主键生成策略或者主键策略为NONE的时候,他跟随的是全局策略
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.NONE)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

那我们来看一下他的全局策略默认是什么,全局配置中 id-type是用于配置主键生成策略的,我们可以看一下id-type的默认值
【MybatisPlus快速入门】—— 进阶入门_第57张图片

通过查看源码发现,id-type的默认值就是雪花算法
【MybatisPlus快速入门】—— 进阶入门_第58张图片

2.1.6 ASSIGN_UUID策略

  • UUID(Universally Unique Identifier)全局唯一标识符,定义为一个字符串主键,采用32位数字组成,编码采用16进制,定义了在时间和空间都完全唯一的系统信息。

  • UUID的编码规则:

    • 1~8位采用系统时间,在系统时间上精确到毫秒级保证时间上的唯一性;
    • 9~16位采用底层的IP地址,在服务器集群中的唯一性;
    • 17~24位采用当前对象的HashCode值,在一个内部对象上的唯一性;
    • 25~32位采用调用方法的一个随机数,在一个对象内的毫秒级的唯一性。
  • 通过以上4种策略可以保证唯一性,在系统中需要用到随机数的地方都可以考虑采用UUID算法。

  • 我们想要演示UUID的效果,需要改变一下表的字段类型和实体类的属性类型

    • 将数据库表的字段类型改为varchar(50)
      【MybatisPlus快速入门】—— 进阶入门_第59张图片

将实体类的属性类型改为String,并指定主键生成策略为 IdType.ASSIGN_UUID

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.ASSIGN_UUID)
    private String id;
    private String name;
    private Integer age;
    private String email;
}

完成数据的添加

@Test
void primaryKey(){
    User user = new User();
    user.setName("Jerry");
    user.setAge(38);
    user.setEmail("[email protected]");
    userMapper.insert(user);
}

我们会发现,成功添加了一条数据,id为uuid类型
【MybatisPlus快速入门】—— 进阶入门_第60张图片

小结: 本章节讲解了主键生成策略,我们可以通过指定主键生成策略来生成不同的主键id,从而达到对于数据进行唯一标识的作用。

2.2 分页

  • 分页操作在实际开发中非常的常见,我们在各种平台和网站中都可以看到分页的效果

    • 例如:京东商城的分页效果
      【MybatisPlus快速入门】—— 进阶入门_第61张图片

    • 例如:百度的分页效果
      在这里插入图片描述

  • 在MybatisPlus中的查询语句是怎么实现的,我们可以通过两种方式实现查询语句

    • 通过MybatisPlus提供的方法来实现条件查询
    • 通过自定义SQL语句的方式来实现查询
  • 接下来我们就来演示这两种分页方式如何实现

2.2.1 分页插件

  • 在大部分场景下,如果我们的SQL没有这么复杂,是可以直接通过MybatisPlus提供的方法来实现查询的,在这种情况下,我们可以通过配置分页插件来实现分页效果

  • 分页的本质就是需要设置一个拦截器,通过拦截器拦截了SQL,通过在SQL语句的结尾添加limit关键字,来实现分页的效果

接下来看一下配置的步骤

1️⃣ 通过配置类来指定一个具体数据库的分页插件,因为不同的数据库的方言不同,具体生成的分页语句也会不同,这里为Mysql数据库

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

2️⃣ 实现分页查询效果

@Test
    void page(){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>();
        //当前页是第几页,每页包含多少条信息
        IPage<User> userPage = new Page<>(2, 3);
        //执行查询
        userMapper.selectPage(userPage, lambdaQueryWrapper);
        //获取分页查询信息
        System.out.println("数据总条数: " + userPage.getTotal());
        System.out.println("总页数: " + userPage.getPages());
        System.out.println("每页显示数: " + userPage.getSize());
        System.out.println("当前是第几页: " + userPage.getCurrent());
        System.out.println("当前页包含的信息: " + userPage.getRecords());

    }

【MybatisPlus快速入门】—— 进阶入门_第62张图片

2.2.2 自定义分页插件

在某些场景下,我们需要自定义SQL语句来进行查询,接下来我们来演示一下自定义SQL的分页操作

1️⃣ 在 UserMapper.xml 映射配置文件中提供查询语句


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mapper.UserMapper">

     <select id="selectByName" resultType="com.powernode.domain.User">
        select * from powershop_user where name = #{name}
     select>

mapper>

2️⃣ 在Mapper接口中提供对应的方法,方法中将IPage对象作为参数传入

@Mapper
public interface UserMapper extends BaseMapper<User> {
       IPage<User> selectByName(IPage<User> page, String name);
}

3️⃣ 表数据为

【MybatisPlus快速入门】—— 进阶入门_第63张图片

4️⃣ 实现分页查询效果

@Test
    void page2(){
        IPage<User> userPage = new Page<>(1, 3);
        userMapper.selectByName(userPage, "Marry");

        System.out.println("当前页: " + userPage.getCurrent());
        System.out.println("每页显示条数: " + userPage.getSize());
        System.out.println("总页数: " + userPage.getPages());
        System.out.println("总条数: " + userPage.getTotal());
        System.out.println("分页数据: " + userPage.getRecords());
    }

【MybatisPlus快速入门】—— 进阶入门_第64张图片

小结: 这里我们学习了两种分页的配置方法,将来以后我们在进行条件查询的时候,可以使用分页的配置进行配置。

2.3 ActiveRecord模式

  • ActiveRecord(活动记录,简称AR),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录 【利用我们的实体类对象去操作数据库中的表】
  • ActiveRecord 一直广受解释型动态语言( PHP 、 Ruby 等)的喜爱,通过围绕一个数据对象进行CRUD操作
  • 而 Java 作为准静态(编译型)语言,对于 ActiveRecord 往往只能感叹其优雅,所以 MP 也在 AR 道路上进行了一定的探索,仅仅需要让实体类继承 Model 类且实现主键指定方法,即可开启 AR 之旅。

那么如何使用 ActiveRecord 模式呢?

1️⃣ 让实体类继承Model类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User extends Model<User> {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  • 我们可以看到,Model类中提供了一些增删改查方法,这样的话我们就可以直接使用实体类对象调用这些增删改查方法
  • 简化了操作的语法,但是他的底层依然是需要UserMapper的,所以持久层接口并不能省略

测试ActiveRecord模式的增删改查

1️⃣ 添加操作

@Test
    void activeRecordAdd(){
        User user = new User();
        user.setName("LaoJiang");
        user.setAge(21);
        user.setEmail("[email protected]");
        user.insert();
    }

【MybatisPlus快速入门】—— 进阶入门_第65张图片

2️⃣ 删除操作

@Test
    void activeRecordDelete(){
        User user = new User();
        user.setId(1646343629209464834L);
        user.deleteById();
    }

【MybatisPlus快速入门】—— 进阶入门_第66张图片

3️⃣ 修改操作

@Test
    void activeRecordUpdate(){
        User user = new User();
        user.setId(1646342593128185857L);
        user.setName("雪花");
        user.updateById();
    }

【MybatisPlus快速入门】—— 进阶入门_第67张图片

4️⃣ 查询操作

@Test
    void activeRecordSelect(){
        User user = new User();
        user.setId(1L);
        user.selectById();
    }

【MybatisPlus快速入门】—— 进阶入门_第68张图片

2.3 SimpleQuery工具类

  • SimpleQuery可以对selectList查询后的结果用Stream流进行了一些封装,使其可以返回一些指定结果,简洁了api的调用

1️⃣ list

演示基于字段封装集合 【在查询的同时支持Stream流的操作】

@Test
    void testList(){
        List<Long> ids = SimpleQuery.list(new LambdaQueryWrapper<User>().eq(User::getName, "Marry"), User::getId);
        System.out.println(ids);
    }

【MybatisPlus快速入门】—— 进阶入门_第69张图片

演示对于封装后的字段进行lambda操作 【获取到的数据再加工,不会修改表中的数据】

@Test
    void testList2(){
        List<String> list = SimpleQuery.list(new LambdaQueryWrapper<User>().eq(User::getName, "Marry"), User::getName, user -> Optional.of(user.getName()).map(String::toLowerCase).ifPresent(user::setName));
        System.out.println(list);
    }

【MybatisPlus快速入门】—— 进阶入门_第70张图片

2️⃣ map

演示将所有的对象以id,实体的方式封装为Map集合

@Test
    void testMap(){
        Map<Long, User> map = SimpleQuery.keyMap(new LambdaQueryWrapper<User>(), User::getId);
        System.out.println(map);
    }

【MybatisPlus快速入门】—— 进阶入门_第71张图片

演示将单个对象以id,实体的方式封装为Map集合

@Test
    void testMap2(){
        //封装一条数据的Map集合
        Map<Long, User> map = SimpleQuery.keyMap(new LambdaQueryWrapper<User>().eq(User::getId, 2L), User::getId);
        System.out.println(map);
    }

【MybatisPlus快速入门】—— 进阶入门_第72张图片

演示只想要id和name组成的map

@Test
    void testMap3(){
        Map<Long, String> map = SimpleQuery.map(new LambdaQueryWrapper<User>(), User::getId, User::getName);
        System.out.println(map);
    }

【MybatisPlus快速入门】—— 进阶入门_第73张图片

3️⃣ Group

@Test
    void testGroup(){
        Map<String, List<User>> group = SimpleQuery.group(new LambdaQueryWrapper<User>(), User::getName);
        System.out.println(group);
    }

【MybatisPlus快速入门】—— 进阶入门_第74张图片

小结: 在这一小节,我们演示了SimpleQuery提供的Stream流式操作的方法,通过这些操作继续为我们提供了查询方面简化的功能

你可能感兴趣的:(MybatisPlus,MybatisPlus,查询专题,主键分页,Java,AR模式)