MyBatisPlus之条件查询(常规查询范围查询模糊查询null值处理等)

Posted 熊凯瑞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatisPlus之条件查询(常规查询范围查询模糊查询null值处理等)相关的知识,希望对你有一定的参考价值。

MyBatisPlus之条件查询

MyBatisPlus之条件查询

1、设置查询条件

1.1 常规格式

  @Test
    public void testInuire() 
        QueryWrapper<User> qw = new QueryWrapper<User>();
         //查询年龄大于等于15岁,小于30岁的用户
        qw.lt("age", 30);
        qw.ge("age", 15);
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);
    

1.2 链式编程格式

  @Test
    public void testInuire() 
        QueryWrapper<User> qw = new QueryWrapper<User>();
         //查询年龄大于等于15岁,小于30岁的用户
        qw.lt("age", 30).ge("age", 15);
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);
    

1.3 lambda格式1

 @Test
    public void testLambda1() 
        QueryWrapper<User> qw = new QueryWrapper<User>();
         //查询年龄大于等于15岁,小于30岁的用户
        qw.lambda().lt(User::getAge, 30).ge(User::getAge,15);
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);
    

1.4 lambda格式2

 @Test
    public void testLambda2() 
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //查询年龄大于等于15岁,小于30岁的用户
        lqw.lt(User::getAge, 30).ge(User::getAge,15);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

2、组合查询条件

2.1 并且

 @Test
    public void testLambda2() 
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //查询年龄大于等于18岁,小于30岁的用户
        lqw.lt(User::getAge, 30).gt(User::getAge,18);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

2.2 或者

 //多条件查询
    @Test
    public void testLambda3() 
        //小于18岁或者大于30岁
        LambdaQueryWrapper<User> lqw2 = new LambdaQueryWrapper<User>();
        lqw2.lt(User::getAge, 18).or().gt(User::getAge, 30);
        List<User> userList2 = userDao.selectList(lqw2);
        System.out.println(userList2);
    

3、条件查询null值判定

3.1 封装User模型的查询条件

观察User类里哪些适合设置上下限

package com.example.maybatisplus_01_quickstart.domain.query;

import com.example.maybatisplus_01_quickstart.domain.User;
import lombok.Data;

@Data
public class UserQuery extends User 
    private Integer age2;


3.2 测试类

package com.example.maybatisplus_01_quickstart;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.maybatisplus_01_quickstart.dao.UserDao;
import com.example.maybatisplus_01_quickstart.domain.User;
import com.example.maybatisplus_01_quickstart.domain.query.UserQuery;
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
public class InquireNotNullTest 
    @Autowired
    private UserDao userDao;

    @Test
    public void inqueryNotNull() 
        //模拟页面传递过来的查询数据
        UserQuery uq = new UserQuery();
        uq.setAge(15);
        uq.setAge2(30);

        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.lt(null != uq.getAge2(), User::getAge, uq.getAge2());
        lqw.gt(null != uq.getAge(), User::getAge, uq.getAge());
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    


3.3 null值处理

3.3.1 条件参数控制

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(null != uq.getAge2(), User::getAge, uq.getAge2());
lqw.gt(null != uq.getAge(), User::getAge, uq.getAge());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);

3.3.2 条件参数控制(链式编程)

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(null != uq.getAge2(), User::getAge, uq.getAge2())
    .gt(null != uq.getAge(), User::getAge, uq.getAge());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);

4、查询投影

4.1 查询结果中包含模型类中 部分属性

 @Test
    public void testQueryProjection1() 
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //这种方式只适合lambda表达式
        lqw.select(User::getId, User::getName, User::getAge);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

4.2 查询结果包含模型类中 未定义的属性

 @Test
    public void testQueryProjection3() 
        QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("count(*) as count, tel");
        lqw.groupBy("tel");
        List<Map<String, Object>> userList = userDao.selectMaps(lqw);
        System.out.println(userList);
 

4.3 原生mysql查询

如果上述方法都无法实现,只能自己手写mysql代码。

4.4 完整测试样例

package com.example.maybatisplus_01_quickstart;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.maybatisplus_01_quickstart.dao.UserDao;
import com.example.maybatisplus_01_quickstart.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Map;

@SpringBootTest
public class QueryProjectionTest 
    @Autowired
    private UserDao userDao;

    //查询投影
    @Test
    public void testQueryProjection1() 
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.select(User::getId, User::getName, User::getAge);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

    @Test
    public void testQueryProjection2() 
        QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("id","name","age");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

    @Test
    public void testQueryProjection3() 
        QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("count(*) as count, tel");
        lqw.groupBy("tel");
        List<Map<String, Object>> userList = userDao.selectMaps(lqw);
        System.out.println(userList);
    



5、查询条件设置(范围匹配、模糊匹配等)

示例

package com.example.maybatisplus_01_quickstart;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.maybatisplus_01_quickstart.dao.UserDao;
import com.example.maybatisplus_01_quickstart.domain.User;
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
public class ConditionalQueryMoreTest 
    @Autowired
    private UserDao userDao;

    //模拟登录操作查询
    @Test
    public void testConditionalQueryMore() 
        //条件查询
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //模拟登录操作
        lqw.eq(User::getName, "西瓜").eq(User::getPassword, "ewfvfv");
        User loginUser = userDao.selectOne(lqw);
        System.out.println(loginUser);
    

    //范围查询
    @Test
    public void testfindRangeQuery() 
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //范围查询 lt(不带等号) le(带等号) gt(不带等号) le(带等号) eq between
        //between中前小后大
        lqw.between(User::getAge,10,22);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

    //模糊查询
    @Test
    public void testfuzzyQuery() 
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //模糊匹配
        //likeRight表示搜索是 西%
        //likeLeft表示搜索是 %西
        lqw.likeRight(User::getName,"西");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    



MyBatisPlus:DQL编程控制(条件查询方式查询投影查询条件设定字段映射与表名映射)

MyBatisPlus

前面我们讲解了
基于MyBatisPlus完成标准Dao的增删改查功能
掌握MyBatisPlus中的分页及条件查询构建 | 黑马程序员
✏点击回顾哦。


1,DQL编程控制

增删改查四个操作中,查询是非常重要的也是非常复杂的操作,这块需要我们重点学习下,这节我们主要学习的内容有:

  • 条件查询方式
  • 查询投影
  • 查询条件设定
  • 字段映射与表名映射

1.1 条件查询

1.1.1 条件查询的类

  • MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合。

这个我们在前面都有见过,比如查询所有和分页查询的时候,都有看到过一个Wrapper类,这个类就是用来构建查询条件的,如下图所示:

那么条件查询如何使用Wrapper来构建呢?

1.1.2 环境构建

在构建条件查询之前,我们先来准备下环境

  • 创建一个SpringBoot项目

  • pom.xml中添加对应的依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.0</version>
        </parent>
        <groupId>com.itheima</groupId>
        <artifactId>mybatisplus_02_dql</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
    
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.4.1</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
    
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    
  • 编写UserDao接口

    @Mapper
    public interface UserDao extends BaseMapper<User> 
    
    
  • 编写模型类

    @Data
    public class User 
        private Long id;
        private String name;
        private String password;
        private Integer age;
        private String tel;
    
    
  • 编写引导类

    @SpringBootApplication
    public class Mybatisplus02DqlApplication 
    
        public static void main(String[] args) 
            SpringApplication.run(Mybatisplus02DqlApplication.class, args);
        
    
    
    
  • 编写配置文件

    # dataSource
    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
        username: root
        password: root
    # mp日志
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
  • 编写测试类

    @SpringBootTest
    class Mybatisplus02DqlApplicationTests 
    
        @Autowired
        private UserDao userDao;
        
        @Test
        void testGetAll()
            List<User> userList = userDao.selectList(null);
            System.out.println(userList);
        
    
    

    最终创建的项目结构为:

  • 测试的时候,控制台打印的日志比较多,速度有点慢而且不利于查看运行结果,所以接下来我们把这个日志处理下:

    • 取消初始化spring日志打印,resources目录下添加logback.xml,名称固定,内容如下:

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
      </configuration>
      

      **说明:**logback.xml的配置内容,不是我们学习的重点,如果有兴趣可以自行百度查询。

    • 取消MybatisPlus启动banner图标

application.yml添加如下内容:

```yml
# mybatis-plus日志控制台输出
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: off # 关闭mybatisplus启动图标
```
  • 取消SpringBoot的log打印

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eRbnn9JF-1656578460686)(assets/1631021269422.png)]

    application.yml添加如下内容:

    spring:
      main:
        banner-mode: off # 关闭SpringBoot启动图标(banner)
    

解决控制台打印日志过多的相关操作可以不用去做,一般会被用来方便我们查看程序运行的结果。

1.1.3 构建条件查询

在进行查询的时候,我们的入口是在Wrapper这个类上,因为它是一个接口,所以我们需要去找它对应的实现类,关于实现类也有很多,说明我们有多种构建查询条件对象的方式,

  1. 先来看第一种:QueryWrapper
@SpringBootTest
class Mybatisplus02DqlApplicationTests 

    @Autowired
    private UserDao userDao;
    
    @Test
    void testGetAll()
        QueryWrapper qw = new QueryWrapper();
        qw.lt("age",18);
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);
    

  • lt: 小于(<) ,最终的sql语句为

    SELECT id,name,password,age,tel FROM user WHERE (age < ?)
    

第一种方式介绍完后,有个小问题就是在写条件的时候,容易出错,比如age写错,就会导致查询不成功

  1. 接着来看第二种:QueryWrapper的基础上使用lambda
@SpringBootTest
class Mybatisplus02DqlApplicationTests 

    @Autowired
    private UserDao userDao;
    
    @Test
    void testGetAll()
        QueryWrapper<User> qw = new QueryWrapper<User>();
        qw.lambda().lt(User::getAge, 10);//添加条件
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);
    

  • User::getAget,为lambda表达式中的,类名::方法名,最终的sql语句为:
SELECT id,name,password,age,tel FROM user WHERE (age < ?)

**注意:**构建LambdaQueryWrapper的时候泛型不能省。

此时我们再次编写条件的时候,就不会存在写错名称的情况,但是qw后面多了一层lambda()调用

  1. 接着来看第三种:LambdaQueryWrapper
@SpringBootTest
class Mybatisplus02DqlApplicationTests 

    @Autowired
    private UserDao userDao;
    
    @Test
    void testGetAll()
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.lt(User::getAge, 10);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

这种方式就解决了上一种方式所存在的问题。

1.1.4 多条件构建

学完了三种构建查询对象的方式,每一种都有自己的特点,所以用哪一种都行,刚才都是一个条件,那如果有多个条件该如何构建呢?

需求:查询数据库表中,年龄在10岁到30岁之间的用户信息

@SpringBootTest
class Mybatisplus02DqlApplicationTests 

    @Autowired
    private UserDao userDao;
    
    @Test
    void testGetAll()
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.lt(User::getAge, 30);
        lqw.gt(User::getAge, 10);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

  • gt:大于(>),最终的SQL语句为

    SELECT id,name,password,age,tel FROM user WHERE (age < ? AND age > ?)
    
  • 构建多条件的时候,可以支持链式编程

    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    lqw.lt(User::getAge, 30).gt(User::getAge, 10);
    List<User> userList = userDao.selectList(lqw);
    System.out.println(userList);
    

需求:查询数据库表中,年龄小于10或年龄大于30的数据

@SpringBootTest
class Mybatisplus02DqlApplicationTests 

    @Autowired
    private UserDao userDao;
    
    @Test
    void testGetAll()
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

  • or()就相当于我们sql语句中的or关键字,不加默认是and,最终的sql语句为:

    SELECT id,name,password,age,tel FROM user WHERE (age < ? OR age > ?)
    

1.1.5 null判定

先来看一张图,

  • 我们在做条件查询的时候,一般会有很多条件可以供用户进行选择查询。
  • 这些条件用户可以选择使用也可以选择不使用,比如我要查询价格在8000以上的手机
  • 在输入条件的时候,价格有一个区间范围,按照需求只需要在第一个价格输入框中输入8000
  • 后台在做价格查询的时候,一般会让 price>值1 and price <值2
  • 因为前端没有输入值2,所以如果不处理的话,就会出现 price>8000 and price < null问题
  • 这个时候查询的结果就会出问题,具体该如何解决?

需求:查询数据库表中,根据输入年龄范围来查询符合条件的记录

用户在输入值的时候,

​ 如果只输入第一个框,说明要查询大于该年龄的用户

​ 如果只输入第二个框,说明要查询小于该年龄的用户

​ 如果两个框都输入了,说明要查询年龄在两个范围之间的用户

思考第一个问题:后台如果想接收前端的两个数据,该如何接收?

我们可以使用两个简单数据类型,也可以使用一个模型类,但是User类中目前只有一个age属性,如:

@Data
public class User 
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;

使用一个age属性,如何去接收页面上的两个值呢?这个时候我们有两个解决方案

方案一:添加属性age2,这种做法可以但是会影响到原模型类的属性内容

@Data
public class User 
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
    private Integer age2;

方案二:新建一个模型类,让其继承User类,并在其中添加age2属性,UserQuery在拥有User属性后同时添加了age2属性。

@Data
public class User 
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;


@Data
public class UserQuery extends User 
    private Integer age2;

环境准备好后,我们来实现下刚才的需求:

@SpringBootTest
class Mybatisplus02DqlApplicationTests 

    @Autowired
    private UserDao userDao;
    
    @Test
    void testGetAll()
        //模拟页面传递过来的查询数据
        UserQuery uq = new UserQuery();
        uq.setAge(10);
        uq.setAge2(30);
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        if(null != uq.getAge2())
            lqw.lt(User::getAge, uq.getAge2());
        
        if( null != uq.getAge()) 
            lqw.gt(User::getAge, uq.getAge());
        
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

上面的写法可以完成条件为非空的判断,但是问题很明显,如果条件多的话,每个条件都需要判断,代码量就比较大,来看MP给我们提供的简化方式:

@SpringBootTest
class Mybatisplus02DqlApplicationTests 

    @Autowired
    private UserDao userDao;
    
    @Test
    void testGetAll()
        //模拟页面传递过来的查询数据
        UserQuery uq = new UserQuery();
        uq.setAge(10);
        uq.setAge2(30);
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.lt(null!=uq.getAge2(),User::getAge, uq.getAge2());
        lqw.gt(null!=uq.getAge(),User::getAge, uq.getAge());
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    

  • lt()方法

condition为boolean类型,返回true,则添加条件,返回false则不添加条件

1.2 查询投影

1.2.1 查询指定字段

目前我们在查询数据的时候,什么都没有做默认就是查询表中所有字段的内容,我们所说的查询投影即不查询所有字段,只查询出指定内容的数据。

具体如何来实现?

@SpringBootTest
class Mybatisplus02DqlApplicationTests 

    @Autowired
    private UserDao userDao;
    
    @Test
    void testGetAll()
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.select(User::getId,User::getName,User::getAge);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);