Mybatis-Plus:持久层数据的高效处理(新手笔记三)--条件查询与分页查询

🤚我的博客

  • 欢迎光临我的博客:https://blog.csdn.net/qq_52434217?type=blog

🥛前言

上一章介绍了常用的API并对其进行了测试。这一章主要的任务是介绍一下前面忘记介绍的mybatis生成的实体类,以级两种高级查询方式:条件查询以及分页查询。这两个高级查询语句都不需要单独编写SQL语句,而是框架自动调用生成SQL语句,从而提高生产效率。

📄MybatisX生成代码实体类的介绍

🔷MybatisX Generator配置

这个地方只在第一章涉及到,但没有细讲。后面仔细考虑一下还是决定讲一下这个插件的使用。
在下面的界面中,可以指定数据表的信息与实体类的一些关系,如ignore table prefixignore table suffix可以去掉表中的前缀和后缀,比如该处的表名为user_info就可以忽略掉后面的_info从而生成User实体类。

点击next进入下一页的配置选项页面,这个页面选择实体类的注释版本以及模板版本。options是注释对实体类的操作,而template则是生成代码的模板。所谓代码模板,是指生成代码包含的东西,这个templateIDEA的自定义template没有区别。而不同的配置则有不同的文件以及模板。


点击FINISH生成代码,可以在上一页的base path下的base package中的relative package中找到实体类。通过插件生成的实体类,自动实现了equals()方法、toString()方法和hashCode()方法,并且实现了序列化接口,这里只贴出数据库中的字段以及序列化ID。

import com.baomidou.mybatisplus.annotation.IdType;  
import com.baomidou.mybatisplus.annotation.TableField;  
import com.baomidou.mybatisplus.annotation.TableId;  
import com.baomidou.mybatisplus.annotation.TableName;  
import java.io.Serializable;  
import lombok.Data;  
  
/**  
 ** @TableName test1  
 */@TableName(value ="test1")  
@Data  
public class Test1 implements Serializable {  
    /**  
     * 唯一id  
     */    
     @TableId(type = IdType.AUTO)  
    private Integer id;  
  
    /**  
     * 用户名  
     */  
    private String username;  
  
    /**  
     * 密码  
     */  
    private String password;  
  
    /**  
     * 姓名  
     */  
    private String name;  
  
    /**  
     *     */  
    private Integer age;  
  
    /**  
     * 1为男,0为女 2保密  
     */  
    private Integer gender;  
  
    /**  
     * 电话  
     */  
    private String phone;  
  
    /**  
     * 邮箱  
     */  
    private String email;  
  
    /**  
     * 头像地址  
     */  
    private String avatar;  
  
    /**  
     *     */  
    private String department;  
  
    /**  
     *     */  
    private Double salary;  
  
    /**  
     *     */  
    private String address;  
  
    /**  
     * 1为正常 0为停用  
     */  
    private Integer status;  
  
    @TableField(exist = false)  
    private static final long serialVersionUID = 1L;

下面对常用注解进行介绍

@TableName()

@TableName()是表名注释,通过该注释指定实体类与数据表的映射关系。只要指定了表明,实体类的类名可以不遵循表的名字。但是数据字段需要一一对应,不能随意改写。下表是该注释的常用属性。

属性类型默认值描述
valueString""表名
resultMapString""xml中resultMapde id
autoReusltMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap ,则不会进行 resultMap 的自动构建并注入)

@TableId()

@TableId注解是专门用在主键上的注解,如果数据库中的主键字段名和实体中的属性名,不一样且不是驼峰之类的对应关系,可以在实体中表示主键的属性上加@TableId注解,并指定@TableId注解的value属性值为表中主键的字段名既可以对应上。

/** 主键 */ 
@TableId("test1_id") 
@TableId(value = "test1_id") 
private Long id;

该注释除了value属性还包括一个type属性,用来设置主键类型、主键的生成策略。id类型如下表所示。

类型名说明
IdType.AUTO数据库自增
IdType.NONEmybatis plus 通过雪花算法设置主键
IdType.INPUT手动赋值
IdType.ASSIGN_IDMP分配ID,类型为LongIntegerString
IdType.ASSIGN_UUID分配UUID,类型为String

📄两种高级查询方式

🔷条件查询

MP的条件查询是采用条件构造器实现的,条件构造器在上一章的API中出现过,但是没有细讲。
所谓条件构造器就是一个实例对象,传入它可以实现条件查询。在MP中有四个条件构造器,分别是QueryWrapper,UpdateQueryWrapper,LambdaQueryWrapper,LambdaUpdateWrapper

接下来具体看看条件构造器的使用。该段代码在单元测试方法或者在serviceImpl的方法中编写,以单元测试为例。

QueryWrapper

@Test  
void conditionalTest(){  
    QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.ge("salary", 15000.0);  
    System.out.println(test1Mapper.selectList(wrapper));  
}
//[User [Hash = 667046708, id=1, username=zhangsan111, password=zhangsan111, name=张三, age=35, gender=1, phone=13512345678, email=13512345678@qq.com, avatar=, department=销售部, salary=15000.0, address=北京市海淀区中关村, status=1, serialVersionUID=1], User [Hash = -1715870505, id=3, username=wangwu111, password=wangwu111, name=王五, age=42, gender=1, phone=13811112222, email=13811112222@qq.com, avatar=, department=研发部, salary=20000.0, address=广东省深圳市南山区科技园, status=1, serialVersionUID=1], User [Hash = 1975952528, id=5, username=liuqi111, password=liuqi111, name=刘七, age=22, gender=0, phone=13655556666, email=13655556666@qq.com, avatar=, department=财务部, salary=18000.0, address=四川省成都市高新区, status=1, serialVersionUID=1]]

这段代码相当于实现的sql语句

SELECT id,username,password,name,age,gender,phone,email,avatar,department,salary,address,status FROM test1 WHERE (salary >= 15000.0)

wrapper的每一个函数都可以接受一个条件判断语句,条件判断放在第一个参数。

@Test  
void conditionalTest(){  
	Double salary = 15000.0;
    QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.ge(salary!=null,"salary", 15000.0);  
    System.out.println(test1Mapper.selectList(wrapper));  
}

这是在mapper中的实现,当然也可以在service中实现。在service中除了wrapper条件,还有一个lambda条件。以listObjs为例。

@Test  
void serviceTest1() {  
    QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.ge("salary", 15000.0);  
    List<User> users = test1Service.listObjs(wrapper, id -> test1Service.getById((Serializable) id));  
    users.forEach(System.out::println);  
}
/*
User [Hash = 667046708, id=1, username=zhangsan111, password=zhangsan111, name=张三, age=35, gender=1, phone=13512345678, email=13512345678@qq.com, avatar=, department=销售部, salary=15000.0, address=北京市海淀区中关村, status=1, serialVersionUID=1]
User [Hash = -1715870505, id=3, username=wangwu111, password=wangwu111, name=王五, age=42, gender=1, phone=13811112222, email=13811112222@qq.com, avatar=, department=研发部, salary=20000.0, address=广东省深圳市南山区科技园, status=1, serialVersionUID=1]
User [Hash = 1975952528, id=5, username=liuqi111, password=liuqi111, name=刘七, age=22, gender=0, phone=13655556666, email=13655556666@qq.com, avatar=, department=财务部, salary=18000.0, address=四川省成都市高新区, status=1, serialVersionUID=1]
*/

这段代码相当于执行了如下的代码

SELECT id,username,password,name,age,gender,phone,email,avatar,department,salary,address,status FROM test1 WHERE (salary >= 15000.0)

这里的lambd函数的参数是一个id值,根据id进行后续的操作。

条件构造器的函数返回实例本身,所以可以采用链式调用。比如下面的代码

@Test  
void serviceTest1() {  
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
			.ge("salary", 15000.0)
			.gt("id",3);  
    List<User> users = test1Service.listObjs(wrapper, id -> test1Service.getById((Serializable) id));  
    users.forEach(System.out::println);  
}

QueryWrapperUpdateQueryWrapper的区别在于使用queryWrapper + 实体类形式可以实现修改,但是无法将列值修改为null值,而使用updateWrapper可以随意设置列的值。
使用queryWrapper

@Test
public void test04() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改
    //UPDATE t_user SET age=?, email=? WHERE username LIKE ? AND age > ? OR email IS NULL)
    queryWrapper
            .like("username", "a")
            .gt("age", 20)
            .or()
            .isNull("email");
    User user = new User();
    user.setAge(18);
    user.setEmail("user@atguigu.com");
    int result = userMapper.update(user, queryWrapper);
    System.out.println("受影响的行数:" + result);
}

使用updateWrapper

@Test
public void testQuick2(){

    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    //将id = 3 的email设置为null, age = 18
    updateWrapper.eq("id",3)
            .set("email",null)  // set 指定列和结果
            .set("age",18);
    //如果使用updateWrapper 实体对象写null即可!
    int result = userMapper.update(null, updateWrapper);
    System.out.println("result = " + result);
}

queryWrapper常用的API接口在下面的表中展示。

函数名说明说明/示例
eqequals ,,等于,=eq("name","老王")–>name=='老王'
nenot equals ,,不等于,<>ne("name","老王") -->name<>'老王'
gtgreat than ,大于,>gt("age",18)–>age>18
gegreat and equal,大于等于,>=ge("age",18)–>age>=18
ltless than,小于, <lt("age",18)–>age<18
leless and equal,小于等于,<=le("age",18)–>age<=18
betweenbetween("age",18,20)–>age between 18 and 20
notBetweennotBetween("age",18,20)–>age not between 18 and 20
likelike("name","王")–>name like '%王%'
notLikenotLike("name","王")–>name not like '%王%'
likeLeftlikeLeft("name","王")–>name like '%王'
likeRightlikeRight("name","王")–>name like '王%'
isNullisNull("name") -->name is null
isNotNullisNotNull("name")–> name is not null
inin("age",{18,19,20})–>age in (18,19,20)
notInnotIn("age",{18,19,20})–>age not in (18,19,20)
inSqlinSql("id","select id from table where id < 3")–>id in (select id from table where id < 3)
notInSqlnotInSql("id","select id from table where id < 3")–>id not in (select id from table where id < 3)
groupBygroupBy("id","name")–>group by id,name
orderByAscorderByAsc("id","name") -->order by id ASC, name ASC
orderByDescorderByDesc("id","name") -->order by id DESC, name DESC
orderByorderBy(boolean condition,boolean isAsc,String colunm,...colunm)orderBy(true,true,"id","name")–>order by id ASC, name ASC
havinghaving("sum(age) >{0}",11) -->having sum(age)>11
or拼接主动调用or表示紧接着的下一个方法不用and连接,如果需要一直使用,则一直需要主动调用
andand嵌套

LambdaQueryWrapper

相比于 QueryWrapper,LambdaQueryWrapper 使用了实体类的属性引用(例如 User::getNameUser::getAge),而不是字符串来表示字段名,这提高了代码的可读性和可维护性。

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();

lambdaQueryWrapper.eq(User::getName, "John")
  .ge(User::getAge, 18)
List<User> userList = userMapper.selectList(lambdaQueryWrapper);

🔷分页查询

分页拦截器配置

使用分页查询,需要在Application入口处配置分页拦截器,当然也可以新建一个配置类将拦截器配置注入。

@Bean  
public MybatisPlusInterceptor mybatisPlusInterceptor() {  
	 // 创建MP拦截器实例
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 
    // 确定数据库类型 
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));  
    return interceptor;  
}

分页查询的使用

@Test  
void pageSelect(){  
    IPage<User> page = new Page<>(1,5);  
    IPage<User> test1IPage = test1Mapper.selectPage(page, null);  
    // 获取当前页的数据
    List<User> records = test1IPage.getRecords();  
    System.out.println("总页数:"+test1IPage.getPages());  
    System.out.println("当前页:"+test1IPage.getCurrent());  
    System.out.println("当前页数量大小"+test1IPage.getSize());  
    System.out.println("获取查询总数"+test1IPage.getTotal());  
    records.forEach(System.out::println);  
}

END

至此,本章内容补充介绍了Mybatis Plus插件的配置以及生成的实例和常用注解。同时在前面的常用API基础之上,实现了条件查询与分页查询。条件查询采用的条件构造器实例进行查询,而分页查询则需要添加MP拦截器,并且需要配置数据库类型才能实现分页操作。下一章将介绍手写mapper中的sql语句,这一章的内容回到了mybatis中。学完手写sql语句后就可以总结mybtis plus相较于mybatis的优势。

公众号

更多内容请关注小夜的公众号,将持续更新java spring全家桶,vue全家桶,python数据分析与爬虫以及js爬虫逆向。
目前正在做小蓝书项目(没错,仿的小红书),后续也会更新项目笔记。

欢迎关注小夜的公众号。


  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值