• Java开发学习(四十二)----MyBatisPlus查询语句之条件查询


    一、条件查询的类

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

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

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

    二、环境构建

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

    • 创建一个SpringBoot项目

        参考Java开发学习(三十五)----SpringBoot快速入门及起步依赖解析

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

      
      <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.0modelVersion>
          <parent>
              <groupId>org.springframework.bootgroupId>
              <artifactId>spring-boot-starter-parentartifactId>
              <version>2.5.0version>
          parent>
          <groupId>com.itheimagroupId>
          <artifactId>mybatisplus_02_dqlartifactId>
          <version>0.0.1-SNAPSHOTversion>
          <properties>
              <java.version>1.8java.version>
          properties>
          <dependencies>
      ​
              <dependency>
                  <groupId>com.baomidougroupId>
                  <artifactId>mybatis-plus-boot-starterartifactId>
                  <version>3.4.1version>
              dependency>
      ​
              <dependency>
                  <groupId>org.springframework.bootgroupId>
                  <artifactId>spring-boot-starterartifactId>
              dependency>
      ​
              <dependency>
                  <groupId>com.alibabagroupId>
                  <artifactId>druidartifactId>
                  <version>1.1.16version>
              dependency>
      ​
              <dependency>
                  <groupId>mysqlgroupId>
                  <artifactId>mysql-connector-javaartifactId>
                  <scope>runtimescope>
              dependency>
      ​
              <dependency>
                  <groupId>org.springframework.bootgroupId>
                  <artifactId>spring-boot-starter-testartifactId>
                  <scope>testscope>
              dependency>
      ​
              <dependency>
                  <groupId>org.projectlombokgroupId>
                  <artifactId>lombokartifactId>
              dependency>
      ​
          dependencies>
      ​
          <build>
              <plugins>
                  <plugin>
                      <groupId>org.springframework.bootgroupId>
                      <artifactId>spring-boot-maven-pluginartifactId>
                  plugin>
              plugins>
          build>
      ​
      project>
      ​
    • 编写UserDao接口

      @Mapper
      public interface UserDao extends BaseMapper {
      }
    • 编写模型类

      @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
      # MybatisPlus日志
      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,名称固定,内容如下:

        
        <configuration>
        configuration>
      • 取消MybatisPlus启动banner图标

        application.yml添加如下内容:

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

        application.yml添加如下内容:

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

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

    三、构建条件查询

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

    1. 先来看第一种:QueryWrapper

    @SpringBootTest
    class Mybatisplus02DqlApplicationTests {
    ​
        @Autowired
        private UserDao userDao;
        
        @Test
        void testGetAll(){
            QueryWrapper qw = new QueryWrapper();
            qw.lt("age",18);
            List 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::getAge,为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);
        }
    }

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

    四、多条件构建

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

    需求:查询数据库表中,年龄在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 > ?)

    五、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);
        }
    }

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

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

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

     

     



    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    SpringCloud-微服务拆分、服务远程调用
    [学习笔记]多元线性回归的梯度下降
    本地缓存框架对比
    领慧立芯LH32M0SXX:压力变送器,测温及称重的单片解决方案
    【springboot】3、自动配置
    golang gin框架1——简单案例以及api版本控制
    Jmeter(四) - 从入门到精通 - 创建网络测试计划(详解教程)
    windows 安装 MySQL 绿色版
    Java版分布式微服务云开发架构 Spring Cloud+Spring Boot+Mybatis 电子招标采购系统源码
    Java多线程编程核心技术
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/16468183.html