• MyBatis-Plus之DQL编程控制


    增删改查四个操作中,查询是非常重要的也是非常复杂的操作,本次介绍的有:

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

    1. 条件查询

    1.1 条件查询的类

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

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

    在这里插入图片描述

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

    1.2 环境构建

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

    • 创建一个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.7.5version>
      		<relativePath/> 
      	parent>
      	<groupId>com.dcxuexigroupId>
      	<artifactId>springboot_mp_03_dqlartifactId>
      	<version>0.0.1-SNAPSHOTversion>
      	<name>springboot_mp_03_dqlname>
      	<description>Demo project for Spring Bootdescription>
      	<properties>
      		<java.version>1.8java.version>
      	properties>
      	<dependencies>
      		<dependency>
      			<groupId>org.springframework.bootgroupId>
      			<artifactId>spring-boot-starterartifactId>
      		dependency>
      
      		<dependency>
      			<groupId>com.baomidougroupId>
      			<artifactId>mybatis-plus-boot-starterartifactId>
      			<version>3.5.2version>
      		dependency>
      
      		<dependency>
      			<groupId>com.alibabagroupId>
      			<artifactId>druidartifactId>
      			<version>1.2.11version>
      		dependency>
      
      		<dependency>
      			<groupId>com.mysqlgroupId>
      			<artifactId>mysql-connector-jartifactId>
      			<scope>runtimescope>
      		dependency>
      		<dependency>
      			<groupId>org.projectlombokgroupId>
      			<artifactId>lombokartifactId>
      			<optional>trueoptional>
      		dependency>
      		<dependency>
      			<groupId>org.springframework.bootgroupId>
      			<artifactId>spring-boot-starter-testartifactId>
      			<scope>testscope>
      		dependency>
      	dependencies>
      
      	<build>
      		<plugins>
      			<plugin>
      				<groupId>org.springframework.bootgroupId>
      				<artifactId>spring-boot-maven-pluginartifactId>
      				<configuration>
      					<excludes>
      						<exclude>
      							<groupId>org.projectlombokgroupId>
      							<artifactId>lombokartifactId>
      						exclude>
      					excludes>
      				configuration>
      			plugin>
      		plugins>
      	build>
      
      project>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
    • 编写UserDao接口

      @Mapper
      public interface UserDao extends BaseMapper<User> {
      }
      
      • 1
      • 2
      • 3
    • 编写模型类

      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      @TableName(value = "platform_user")
      public class User {
          @TableId(type = IdType.AUTO)
          private Integer userId;
          private String email;
          private String userName;
          private String branchName;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 编写引导类

      @SpringBootApplication
      public class SpringbootMp03DqlApplication {
      
      	public static void main(String[] args) {
      		SpringApplication.run(SpringbootMp03DqlApplication.class, args);
      	}
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 编写配置文件

      spring:
        datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/mybatis
          username: root
          password: root
          type: com.alibaba.druid.pool.DruidDataSource
      mybatis-plus:
        configuration:
          log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #打印SQL日志到控制台
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    • 编写测试类

      @SpringBootTest
      class SpringbootMp03DqlApplicationTests {
      
      	@Autowired
      	private UserDao userDao;
      
      	@Test
      	void testSelectById() {
      		User user = userDao.selectById(146);
      		System.out.println("user = " + user);
      	}
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      最终创建的项目结构为:

    在这里插入图片描述

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

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

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

        在这里插入图片描述

        application.yml添加如下内容:

        mybatis-plus:
          configuration:
            log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #打印SQL日志到控制台
          global-config:
            banner: false # 关闭mybatisplus启动图标
        
        • 1
        • 2
        • 3
        • 4
        • 5
      • 取消SpringBoot的log打印

        在这里插入图片描述

        application.yml添加如下内容:

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

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

    1.3 构建条件查询

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

    在这里插入图片描述

    1. 先来看第一种:QueryWrapper
    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    		queryWrapper.lt("user_id",10);
    		List<User> userList = userDao.selectList(queryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • lt:小于(<) ,最终的sql语句为

      SELECT user_id,email,user_name,branch_name FROM platform_user WHERE (user_id < ?)
      
      • 1

    在这里插入图片描述

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

    1. 接着来看第二种:QueryWrapper的基础上使用lambda
    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    		//queryWrapper.lt("user_id",10);
    		queryWrapper.lambda().lt(User::getUserId,10);
    		List<User> userList = userDao.selectList(queryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • User::getAget,为lambda表达式中的,类名::方法名,最终的sql语句为:
    SELECT user_id,email,user_name,branch_name FROM platform_user WHERE (user_id < ?)
    
    • 1

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

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

    1. 接着来看第三种:LambdaQueryWrapper
    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		//QueryWrapper queryWrapper = new QueryWrapper();
    		//queryWrapper.lt("user_id",10);
    		//queryWrapper.lambda().lt(User::getUserId,10);
    		LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    		lambdaQueryWrapper.lt(User::getUserId,10);
    		List<User> userList = userDao.selectList(lambdaQueryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

    1.4 多条件构建

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

    需求:查询数据库表中,用户ID在10到20之间的用户信息

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    		lambdaQueryWrapper.gt(User::getUserId,10);
    		lambdaQueryWrapper.lt(User::getUserId,20);
    		List<User> userList = userDao.selectList(lambdaQueryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • gt:大于(>),最终的SQL语句为

      SELECT user_id,email,user_name,branch_name FROM platform_user WHERE (user_id > ? AND user_id < ?)
      
      • 1
    • 构建多条件的时候,可以支持链式编程

      @SpringBootTest
      class SpringbootMp03DqlApplicationTests {
      
      	@Autowired
      	private UserDao userDao;
      
      	@Test
      	void testSelectAll(){
      		LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
      		lambdaQueryWrapper.gt(User::getUserId,10).lt(User::getUserId,20);
      		//lambdaQueryWrapper.lt(User::getUserId,20);
      		List<User> userList = userDao.selectList(lambdaQueryWrapper);
      		userList.forEach(System.out::println);
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

    需求:查询数据库表中,用户ID小于10或大于20的数据

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    		lambdaQueryWrapper.lt(User::getUserId,10).or().gt(User::getUserId,20);
    		//lambdaQueryWrapper.lt(User::getUserId,20);
    		List<User> userList = userDao.selectList(lambdaQueryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • or()就相当于我们sql语句中的or关键字,不加默认是and,最终的sql语句为:

      SELECT user_id,email,user_name,branch_name FROM platform_user WHERE (user_id < ? OR user_id > ?)
      
      • 1

    1.5 null判定

    在这里插入图片描述

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

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

    用户在输入值的时候,

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

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

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

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

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

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email;
        private String userName;
        private String branchName;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

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

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email;
        private String userName;
        private String branchName;
        private Integer userId2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email;
        private String userName;
        private String branchName;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    @Data
    public class QueryUser extends User {
        private Integer userId2;
    }
    
    • 1
    • 2
    • 3
    • 4

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

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		//模拟页面传递过来的查询数据
    		QueryUser queryUser = new QueryUser();
    		queryUser.setUserId2(50);
    		queryUser.setUserId(20);
    
    		LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    		if (null != queryUser.getUserId2()){
    			lambdaQueryWrapper.lt(User::getUserId,queryUser.getUserId2());
    		}
    		if (null != queryUser.getUserId()){
    			lambdaQueryWrapper.gt(User::getUserId,queryUser.getUserId());
    		}
    
    		List<User> userList = userDao.selectList(lambdaQueryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		//模拟页面传递过来的查询数据
    		QueryUser queryUser = new QueryUser();
    		queryUser.setUserId2(50);
    		queryUser.setUserId(20);
    
    		LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    		lambdaQueryWrapper.lt(null != queryUser.getUserId2(),User::getUserId,queryUser.getUserId2());
    		lambdaQueryWrapper.gt(null != queryUser.getUserId(),User::getUserId,queryUser.getUserId());
    
    		List<User> userList = userDao.selectList(lambdaQueryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • lt()方法

      在这里插入图片描述

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

    2. 查询投影

    2.1 查询指定字段

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

    具体如何来实现:

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    		lambdaQueryWrapper.select(User::getUserName,User::getEmail);
    
    		List<User> userList = userDao.selectList(lambdaQueryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • select(…)方法用来设置查询的字段列,可以设置多个,最终的sql语句为:

      SELECT user_name,email FROM platform_user
      
      • 1
    • 如果使用的不是lambda,就需要手动指定字段

      @SpringBootTest
      class SpringbootMp03DqlApplicationTests {
      
      	@Autowired
      	private UserDao userDao;
      
      	@Test
      	void testSelectAll(){
      		//LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
      		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
      		queryWrapper.select("user_name","email");
      
      		List<User> userList = userDao.selectList(queryWrapper);
      		userList.forEach(System.out::println);
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 最终的sql语句为:SELECT user_name,email FROM platform_user

    2.2 聚合查询

    需求:聚合函数查询,完成count、max、min、avg、sum的使用

    count:总记录数

    max:最大值

    min:最小值

    avg:平均值

    sum:求和

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    		//queryWrapper.select("count(*) as num");
    		//queryWrapper.select("max(user_id) as maxId");
    		//queryWrapper.select("min(user_id) as minId");
    		//queryWrapper.select("avg(user_id) as avgId");
    		queryWrapper.select("sum(user_id) as sumId");
    
    		List<Map<String, Object>> mapList = userDao.selectMaps(queryWrapper);
    		System.out.println(mapList);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    为了在做结果封装的时候能够更简单,我们将上面的聚合函数都起了个名称,方面后期来获取这些数据

    2.3 分组查询

    需求:分组查询,完成 group by的查询使用

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    		queryWrapper.select("count(*) as num , branch_name");
    		queryWrapper.groupBy("branch_name");
    
    		List<Map<String, Object>> mapList = userDao.selectMaps(queryWrapper);
    		System.out.println(mapList);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • groupBy为分组,最终的sql语句为

      SELECT count(*) as num , branch_name FROM platform_user GROUP BY branch_name
      
      • 1

    注意:

    • 聚合与分组查询,无法使用lambda表达式来完成
    • MP只是对MyBatis的增强,如果MP实现不了,我们可以直接在DAO接口中使用MyBatis的方式实现

    3. 查询条件

    前面我们只使用了lt()和gt(),除了这两个方法外,MP还封装了很多条件对应的方法,重点把MP提供的查询条件方法进行介绍下。

    MP的查询条件有很多:

    • 范围匹配(> 、 = 、between)
    • 模糊匹配(like)
    • 空判定(null)
    • 包含性匹配(in)
    • 分组(group)
    • 排序(order)
    • ……

    3.1 等值查询

    需求:根据用户名和归属公司查询用户信息

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    		queryWrapper.lambda().eq(User::getUserName,"fenjinba").eq(User::getBranchName, "奋进吧");
    
    		User user = userDao.selectOne(queryWrapper);
    		System.out.println("user = " + user.toString());
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • eq(): 相当于 =,对应的sql语句为

      SELECT user_id,email,user_name,branch_name FROM platform_user WHERE (user_name = ? AND branch_name = ?)
      
      • 1
    • selectList:查询结果为多个或者单个

    • selectOne:查询结果为单个

    3.2 范围查询

    需求:对年龄进行范围查询,使用lt()、le()、gt()、ge()、between()进行范围查询

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    		queryWrapper.lambda().between(User::getUserId,10,20);
    
    		List<User> userList = userDao.selectList(queryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • gt():大于(>)

    • ge():大于等于(>=)

    • lt():小于(<)

    • lte():小于等于(<=)

    • between():between ? and ?

      SELECT user_id,email,user_name,branch_name FROM platform_user WHERE (user_id BETWEEN ? AND ?)
      
      • 1

    3.3 模糊查询

    需求:查询表中branch_name属性的值以上海开头的用户信息,使用like进行模糊查询

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    		//queryWrapper.lambda().between(User::getUserId,10,20);
    		queryWrapper.lambda().like(User::getBranchName,"上海");
    
    		List<User> userList = userDao.selectList(queryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • like():前后加百分号,如 %上海%
    • likeLeft():前面加百分号,如 %上海
    • likeRight():后面加百分号,如 上海%

    3.4 排序查询

    需求上海查询所有数据,然后按照user_id降序

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    
    		//condition :条件,返回boolean,当condition为true,进行排序,如果为false,则不排序
    		//isAsc:是否为升序,true为升序,false为降序
    		//columns:需要操作的列
    		queryWrapper.lambda().orderBy(true,true,User::getUserId);
    
    		List<User> userList = userDao.selectList(queryWrapper);
    		userList.forEach(System.out::println);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    除了上面演示的这种实现方式,还有很多其他的排序方法可以被调用,如图:

    在这里插入图片描述

    • orderBy排序
      • condition:条件,true则添加排序,false则不添加排序
      • isAsc:是否为升序,true升序,false降序
      • columns:排序字段,可以有多个
    • orderByAsc/Desc(单个column):按照指定字段进行升序/降序
    • orderByAsc/Desc(多个column):按照多个字段进行升序/降序
    • orderByAsc/Desc
      • condition:条件,true添加排序,false不添加排序
      • 多个columns:按照多个字段进行排序

    除了上面介绍的这几种查询条件构建方法以外还会有很多其他的方法,比如isNull,isNotNull,in,notIn等等方法可供选择,具体参考官方文档的条件构造器来使用,暂时不介绍了。

    4. 映射匹配兼容性

    前面我们已经能从表中查询出数据,并将数据封装到模型类中,这整个过程涉及到一张表和一个模型类:

    CREATE TABLE `user` (
      `user_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
      `email` varchar(60) NOT NULL DEFAULT '',
      `user_name` varchar(60) NOT NULL DEFAULT '',
      `branch_name` varchar(30) DEFAULT NULL,
      PRIMARY KEY (`user_id`) USING BTREE,
      KEY `idx_platform_user_id_name` (`user_name`) USING BTREE,
      KEY `idx_platform_user_email` (`email`) USING BTREE
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    public class User {
        private Integer userId;
        private String email;
        private String userName;
        private String company;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    之所以数据能够成功的从表中获取并封装到模型对象中,原因是表的字段列名和模型类的属性名一样。

    那么问题就来了:

    问题1:表字段与编码属性设计不同步

    当表的列名和模型类的属性名发生不一致,就会导致数据封装不到模型对象,这个时候就需要其中一方做出修改,那如果前提是两边都不能改又该如何解决?

    MP给我们提供了一个注解@TableField,使用该注解可以实现模型类属性名和表的列名之间的映射关系

    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email;
        private String userName;
    
        @TableId(value = "branch_name")
        private String company;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    问题2:编码中添加了数据库中未定义的属性

    当模型类中多了一个数据库表不存在的字段,就会导致生成的sql语句中在select的时候查询了数据库不存在的字段,程序运行就会报错,错误信息为:nested exception is java.sql.SQLSyntaxErrorException: Unknown column '多出来的字段名称' in 'field list'

    具体的解决方案用到的还是@TableField注解,它有一个属性叫exist,设置该字段是否在数据库表中存在,如果设置为false则不存在,生成sql语句查询的时候,就不会再查询该字段了。

    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email;
        private String userName;
    
        @TableField(value = "branch_name")
        private String company;
    
        @TableField(exist = false)
        private String address; //该字段数据表中不存在
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    问题3:采用默认查询开放了更多的字段查看权限

    查询表中所有的列的数据,就可能把一些敏感数据查询到返回给前端,这个时候我们就需要限制哪些字段默认不要进行查询。解决方案是@TableField注解的一个属性叫select,该属性设置默认是否需要查询该字段的值,true(默认值)表示默认查询该字段,false表示默认不查询该字段。

    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
    
        @TableField(select = false)
        private String email; //不查询该字段
    
        private String userName;
    
        @TableField(value = "branch_name")
        private String company;
    
        @TableField(exist = false)
        private String address; //该字段数据表中不存在
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    知识点1:@TableField

    名称@TableField
    类型属性注解
    位置模型类属性定义上方
    作用设置当前属性对应的数据库表中的字段关系
    相关属性value(默认):设置数据库表字段名称
    exist:设置属性在数据库表字段中是否存在,默认为true,此属性不能与value合并使用
    select:设置属性是否参与查询,此属性与select()映射配置不冲突

    问题4::表名与编码开发设计不同步

    该问题主要是表的名称和模型类的名称不一致,导致查询失败,这个时候通常会报如下错误信息:

    CREATE TABLE `platform_user` (
      `user_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
      `email` varchar(60) NOT NULL DEFAULT '',
      `user_name` varchar(60) NOT NULL DEFAULT '',
      `branch_name` varchar(30) DEFAULT NULL,
      PRIMARY KEY (`user_id`) USING BTREE,
      KEY `idx_platform_user_id_name` (`user_name`) USING BTREE,
      KEY `idx_platform_user_email` (`email`) USING BTREE
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
    
        @TableField(select = false)
        private String email; //不查询该字段
    
        private String userName;
    
        @TableField(value = "branch_name")
        private String company;
    
        @TableField(exist = false)
        private String address; //该字段数据表中不存在
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    nested exception is java.sql.SQLSyntaxErrorException: Table 'mybatis.user' doesn't exist

    翻译过来就是数据库中的表不存在。

    解决方案是使用MP提供的另外一个注解@TableName来设置表与模型类之间的对应关系。

    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
    
        @TableField(select = false)
        private String email; //不查询该字段
    
        private String userName;
    
        @TableField(value = "branch_name")
        private String company;
    
        @TableField(exist = false)
        private String address; //该字段数据表中不存在
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    知识点2:@TableName

    名称@TableName
    类型类注解
    位置模型类定义上方
    作用设置当前类对应于数据库表关系
    相关属性value(默认):设置数据库表名称

    代码演示

    接下来我们使用案例的方式把刚才的知识演示下:

    步骤1:修改数据库表user为platform_user

    直接查询会报错,原因是MP默认情况下会使用模型类的类名首字母小写当表名使用。

    在这里插入图片描述

    步骤2:模型类添加@TableName注解

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email; 
        private String userName;
        private String branchName;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    步骤3:将字段branch_name修改成company

    直接查询会报错,原因是MP默认情况下会使用模型类的属性名当做表的列名使用

    在这里插入图片描述

    步骤4:使用@TableField映射关系

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email; 
        private String userName;
        
        @TableField(value = "branch_name")
        private String company;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    步骤5:添加一个数据库表不存在的字段

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email; 
        private String userName;
        
        @TableField(value = "branch_name")
        private String company;
        
        private String address; //该字段数据表中不存在
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    直接查询会报错,原因是MP默认情况下会查询模型类的所有属性对应的数据库表的列,而address不存在

    在这里插入图片描述

    步骤6:使用@TableField排除字段

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
        private String email; 
        private String userName;
        
        @TableField(value = "branch_name")
        private String company;
        
        @TableField(exist = false)
        private String address; //该字段数据表中不存在
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    步骤7:查询时将email隐藏

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "platform_user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Integer userId;
    
        @TableField(select = false)
        private String email; //不查询该字段
    
        private String userName;
    
        @TableField(value = "branch_name")
        private String company;
    
        @TableField(exist = false)
        private String address; //该字段数据表中不存在
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    项目代码

  • 相关阅读:
    linux库-----树莓派外设开发
    线程池底层原理详解与源码分析(补充部分---ScheduledThreadPoolExecutor类分析)
    如何将本地项目推送到gitee仓库
    HostMonitor邮件告警详细解读----生产可用
    【web3py】批量创建eth账号
    连续数字阶乘求和
    Pinia的学习与项目的创建
    ArcGIS for Android 禁止地图旋转
    Redis群集
    ASP.NET 6 使用工作单元操作 MongoDB
  • 原文地址:https://blog.csdn.net/qq_37726813/article/details/128028110