MyBatis-Plus之DQL编程控制

news2025/8/8 8:23:40

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

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

1. 条件查询

1.1 条件查询的类

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

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

在这里插入图片描述

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

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.7.5</version>
    		<relativePath/> <!-- lookup parent from repository -->
    	</parent>
    	<groupId>com.dcxuexi</groupId>
    	<artifactId>springboot_mp_03_dql</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>springboot_mp_03_dql</name>
    	<description>Demo project for Spring Boot</description>
    	<properties>
    		<java.version>1.8</java.version>
    	</properties>
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>com.baomidou</groupId>
    			<artifactId>mybatis-plus-boot-starter</artifactId>
    			<version>3.5.2</version>
    		</dependency>
    
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>druid</artifactId>
    			<version>1.2.11</version>
    		</dependency>
    
    		<dependency>
    			<groupId>com.mysql</groupId>
    			<artifactId>mysql-connector-j</artifactId>
    			<scope>runtime</scope>
    		</dependency>
    		<dependency>
    			<groupId>org.projectlombok</groupId>
    			<artifactId>lombok</artifactId>
    			<optional>true</optional>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    				<configuration>
    					<excludes>
    						<exclude>
    							<groupId>org.projectlombok</groupId>
    							<artifactId>lombok</artifactId>
    						</exclude>
    					</excludes>
    				</configuration>
    			</plugin>
    		</plugins>
    	</build>
    
    </project>
    
  • 编写UserDao接口

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

    @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;
    }
    
  • 编写引导类

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

    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日志到控制台
    
  • 编写测试类

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectById() {
    		User user = userDao.selectById(146);
    		System.out.println("user = " + user);
    	}
    
    }
    

    最终创建的项目结构为:

在这里插入图片描述

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

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

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
      </configuration>
      
    • 取消MybatisPlus启动banner图标

      在这里插入图片描述

      application.yml添加如下内容:

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

      在这里插入图片描述

      application.yml添加如下内容:

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

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

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);
	}
}
  • lt:小于(<) ,最终的sql语句为

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

在这里插入图片描述

第一种方式介绍完后,有个小问题就是在写条件的时候,容易出错,比如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);
	}
}
  • User::getAget,为lambda表达式中的,类名::方法名,最终的sql语句为:
SELECT user_id,email,user_name,branch_name FROM platform_user WHERE (user_id < ?)

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

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

  1. 接着来看第三种:LambdaQueryWrapper
@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);
		LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.lt(User::getUserId,10);
		List<User> userList = userDao.selectList(lambdaQueryWrapper);
		userList.forEach(System.out::println);
	}
}

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

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);
	}
}
  • gt:大于(>),最终的SQL语句为

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

    @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);
    	}
    }
    

需求:查询数据库表中,用户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);
	}
}
  • or()就相当于我们sql语句中的or关键字,不加默认是and,最终的sql语句为:

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

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;
}

使用一个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;
}

方案二:新建一个模型类,让其继承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;
}
@Data
public class QueryUser extends User {
    private Integer userId2;
}

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

@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);
	}
}

上面的写法可以完成条件为非空的判断,但是问题很明显,如果条件多的话,每个条件都需要判断,代码量就比较大,来看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);
	}
}
  • 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);
	}
}
  • select(…)方法用来设置查询的字段列,可以设置多个,最终的sql语句为:

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

    @SpringBootTest
    class SpringbootMp03DqlApplicationTests {
    
    	@Autowired
    	private UserDao userDao;
    
    	@Test
    	void testSelectAll(){
    		//LambdaQueryWrapper<User> 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);
    	}
    }
    
    • 最终的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);
	}
}

在这里插入图片描述

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

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);
	}
}
  • groupBy为分组,最终的sql语句为

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

注意:

  • 聚合与分组查询,无法使用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());
	}
}
  • eq(): 相当于 =,对应的sql语句为

    SELECT user_id,email,user_name,branch_name FROM platform_user WHERE (user_name = ? AND branch_name = ?)
    
  • 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);
	}
}
  • gt():大于(>)

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

  • lt():小于(<)

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

  • between():between ? and ?

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

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);
	}
}
  • 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);
	}
}

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

在这里插入图片描述

  • 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;
public class User {
    private Integer userId;
    private String email;
    private String userName;
    private String company;
}

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

那么问题就来了:

问题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;
}

问题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; //该字段数据表中不存在
}

问题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:@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;
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; //该字段数据表中不存在
}

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; //该字段数据表中不存在
}

知识点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;
}

步骤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;
}

步骤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; //该字段数据表中不存在
}

直接查询会报错,原因是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; //该字段数据表中不存在
}

步骤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; //该字段数据表中不存在
}

项目代码

  • gitee 代码下载

  • github 代码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/34329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker的镜像管理

Docker的镜像管理Docker的镜像管理一、Docker的镜像管理命令1.1 搜索镜像1.2 获取镜像1.3 镜像加速下载1.4 查看镜像信息1.5 获取镜像详细信息1.6 为本地的镜像添加新的标签1.7 删除镜像1.8 批量删除镜像1.8 存出镜像&#xff1a;将镜像保存成为本地文件1.9 载入镜像&#xff1…

如何用人工智能帮你剪视频?

痛点制作视频已经好几年了&#xff0c;但是剪片子一直是让我比较头疼的事儿。以前我一直搞不清楚&#xff0c;视频为什么需要剪辑。曾经有一段儿&#xff0c;我是这么录视频的。如果讲的时候出现了磕绊&#xff0c;或者有些展示过程出现问题&#xff0c;我怎么办&#xff1f;我…

Kotlin 开发Android app(十一):Android控件RecyclerView

Android 中的控件非常的丰富&#xff0c;我们会陆陆续续的进行介绍&#xff0c;从第九节开始&#xff0c;关于Kotlin 的语法特性就差不多结束&#xff0c;后面如果有发现需要说明的语法&#xff0c;再进行相关的补充。 在Android的控件中&#xff0c;RecyclerView算是一个大控…

常见性能测试指标

性能测试核心指标&#xff1a; 吞吐量 响应时间&#xff08;Rsponse Time&#xff09; 并发处理能力 资源占用能力 测试中的时间占比&#xff1a; 40%——性能测试分析 30%——测试执行 30%——测试结果分析 而全链路监控就是只要和系统相关的全部需要监控到。 吞吐量 单位…

JavaIO流:NIO梳理

NIO 也叫 Non-Blocking IO 是同步非阻塞的 IO 模型。线程发起 IO 请求后&#xff0c;立即返回。同步指的是必须等待 IO 缓冲区内的数据就绪&#xff0c;而非阻塞指的是&#xff0c;用户线程不原地等待 IO 缓冲区&#xff0c;可以先做一些其他操作&#xff0c;但是要定时轮询检查…

ctfshow XSS web316~web333

web316 反射性 XSS 题目提示我们要以 admin 获取 奇葩的是用网上的 xss 平台&#xff0c;获取的 cookie 全是自己的。 可以在自己的服务器上&#xff0c;创建一个接收 cookie 的 PHP 文件&#xff1a; <?php $cookie $_GET[cookie]; $time date(Y-m-d h:i:s, time()…

Mysql_实战_从入门到高级

Mysql_实战_从入门到高级 文章目录Mysql_实战_从入门到高级第二章 基于SpringBootMySQL实战案例第1集 SpringBoot项目搭建第2集 ORM关系对象映射做了什么&#xff1f;第3集 Mysql与Java实战之JdbcTemplate整合方式第4集 Mysql与JdbcTemplate增删改查第5集 HTTP应用增删改查协议…

Spring之AOP的切点、通知、切点表达式以及知识要点

1.2.1、需要编写的内容 编写核心业务代码&#xff08;目标类的目标方法&#xff09; 编写切面类&#xff0c;切面类中有通知(增强功能方法) 在配置文件中&#xff0c;配置织入关系&#xff0c;即将哪些通知与哪些连接点进行结合 1.2.2、AOP 技术实现的内容 Spring 框架监控…

如何用JavaScripte和HTML 实现一整套的考试答题卡和成绩表

相信在学校的你都有这样的体验&#xff0c;临近考试&#xff0c;要疯狂的“背诵”否则成绩单就要挂零&#xff0c;因为答题卡全部涂抹都是错的。 那么毕业多年的你&#xff0c;没有了考试&#xff0c;有没有一丝怀念涂答题卡的时候&#xff0c;有没有好奇这个答题卡到底如何制作…

【附源码】计算机毕业设计JAVA疫情下智慧社区系统

【附源码】计算机毕业设计JAVA疫情下智慧社区系统 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA …

使用Vue3封装的切换主题开关

组件介绍 第一次封装正经组件&#xff0c;更加深刻地感受到了Vue的强大及其带来的便利&#xff0c;记录一下&#x1f604;打算多搞几个练Vue3 这是一个绑定了两个自定义事件、两个具名插槽的组件&#xff0c;可以切换白天、黑夜两种状态&#xff0c;因为放了两个slot插槽因此…

Java接口的相关知识

文章目录接口的概念语法规则接口的使用接口的特征实现多个接口接口间的继承接口使用实例Clonable 接口和深拷贝抽象类和接口的区别Object获取对象信息&#xff08;toString&#xff09;对象比较equals方法接口的概念 在生活中&#xff0c;接口的例子比比皆是&#xff0c;比如&…

总结:Prometheus之PromQL操作符

一、介绍 使用PromQL除了能够方便的按照查询和过滤时间序列以外&#xff0c;PromQL还支持丰富的操作符&#xff0c;这些操作符包括&#xff1a;数学运算符&#xff0c;逻辑运算符&#xff0c;布尔运算符等等。 二、数学运算 (加法)- (减法)* (乘法)/ (除法)% (求余)^ (幂运算…

macOS Outlook 查看邮件的源码 HTML源码

文章目录一句话Intro系统及软件版本macOS 12.6 M1 chipOutlook 16.67 (22111300)操作方式邮件正文 demo一句话 查看Outlook中HTML格式邮件的HTML源代码&#xff1a; Windows&#xff1a;Actions > Other Actions > View Source macOS&#xff1a;鼠标右击要查看的邮件 &…

提高工作效率,让你快速获得Hypermesh二次开发能力!

众所周知&#xff0c;目前电子产品种类很多&#xff0c;产品更新换代很快&#xff0c;已经步入快消品行列&#xff0c;这必然导致每个厂商对于产品开发周期的要求很严格&#xff0c;其次消费者对产品越来越挑剔&#xff0c;对产品的创新性要求很高&#xff0c;如果产品的同质化…

三肽Isovaleryl-Val-Val-Sta-乙酯化、120849-36-7

三肽Isovaleryl-Val-Val-Sta-乙酯化 编号&#xff1a;154080 CAS号&#xff1a;120849-36-7 三字母&#xff1a;Isobutyricacid-Val-Val-Sta-OEt 描 述&#xff1a;胃酶抑素类似物 SR 42128 抑制肾素活性。编号: 154080 中文名称: 三肽Isovaleryl-Val-Val-Sta-乙酯化 CAS号: 12…

JVM类加载(类加载过程、双亲委派模型)

系列文章目录 JVM的内存区域划分_crazy_xieyi的博客-CSDN博客 文章目录 一、类加载过程二、关于类加载的典型试题三、双亲委派模型一、类加载过程 对于一个类来说&#xff0c;它的生命周期是这样的&#xff1a;1.加载 “加载”&#xff08;Loading&#xff09;阶段是整个“类加…

MyBatis-核心配置文件mybatis-config.xml主要参数详解

1.全局配置文件 全局配置文件&#xff0c;见名知意就是对当前MyBatis的一些全局属性进行设置。也就是对各种数据操作进行统一规定。 全局配置文件包含了全局设置&#xff08;setting&#xff09;和properties两个大的部分&#xff0c;通过这两个大的部分动态的影响MyBatis的行…

安装Centos7

大部分运行环境都是centos&#xff0c;自己最近装了太多次centso&#xff0c;记录一下。 目录一、安装VMware二、下载Centos7镜像三、新建虚拟机四、配置Centos4.1 开启虚拟机4.2 配置安装语言4.3 安装图形界面4.4 设置磁盘分区4.5 开启网络4.6 配置root密码一、安装VMware VM…

git学习(一)

git学习之基本配置以及简单推拉操作 1 git的基本配置 1.1 配置提交者的姓名 1.1.1 语法 git config --global user.name "姓名"1.1.2 示例代码 git config --global user.name "张三"1.1.3 示例代码运行截图 1.2 配置提交者的邮箱 1.2.1 语法 git c…