当前位置:   article > 正文

Mybatis plus 分页集成及基本使用总结 注解连表查询分页案例 QueryWrapper,LambdaQueryWrapper,selectMap和selectObjs_querywrapper 联表查询

querywrapper 联表查询

一、简介

Mybaits-plus 是mybits 的升级版,从mybaits 升级到mybaits-plus 可以实现平滑升级

Mybaits-plus 本身提供大量的基本查询方法以及强大的 Wrapper(包装) 类 用于查询的 QueryWrapper 以及 更新的 UpdateWrapper ,使用Wrapper 基本已经可以构建大部分条件了。

几乎可以实现很少代码,很多功能自动提供

使得一般的查询几乎不需要写 XML 直接使用代码包装完成。

同时支持各类注解帮助完成实体以及查询语句的构建。

二、环境

spring-boot

三、Maven 依赖

可以使用properties 的方式指定版本也可以去除perperties 直接写入版本到下面的 version 中

        <!-- 版本 -->
    <properties>
        <mybatis-plus.version>3.5.2</mybatis-plus.version>
        <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
    </properties>

        <!-- mybaits-plus 主要依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!-- MybatisPlus代码生成器  可选,不是必要的-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatis-plus-generator.version}</version>
        </dependency>
        <!-- MybatisPlus代码生成器默认生成引擎的依赖 可选,不是必要的 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>${velocity.version}</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

四、使用分页时需要添加的配置类

注意下面的导包来源路径,不要导错

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
    	// 新增mybatis-plus 插件
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 新增分页插件  并指定数据库类型
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setOptimizeJoin(true);
        // 查询分页最大限制 -1 时不做限制
        paginationInnerInterceptor.setMaxLimit(500L);
        // 加入分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

到这里基本完成配置

同时也可以在这里使用注解指出配置的实体类扫描路径和基本Mapper 类的路径
上面也可以如下示例:

@Configuration
// 指定实体类(就是和数据库中表对应的类)扫描路径  类所在包路径
@EntityScan("org.aurora.entity")
// 基本的Mapper 类的所在包路径
@MapperScan(basePackages = "org.aurora.mapper", markerInterface = BaseMapper.class)
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
    	// 新增mybatis-plus 插件
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 新增分页插件  并指定数据库类型
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setOptimizeJoin(true);
        // 查询分页最大限制 -1 时不做限制
        paginationInnerInterceptor.setMaxLimit(500L);
        // 加入分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

包路径为多个同级目录下的多个mapper 时可以使用 ** 指代所有
例如:org.aurora.**.mapper
说明是 org.aurora 下所有的第一层同级包下,每个包下的 mapper 包下

例如我的测试用包路径如下
在这里插入图片描述
同时:上面的
@MapperScan 也可以加到 springboot的启动类上

如下
(注意:Application 启动类一定在 最外层,从图上可以看出和项目 resources 的层级关系,java 和 resources 同级,该类一定在一层包的最外面一层)
在这里插入图片描述
@MapperScan 也可以如下加入

@MapperScan("org.aurora.mapper")
// spring 中其他通过注解等方法注入spring容器的类的扫描路径 一般放到最大的路径上 让扫描整个项目也省事
@ComponentScan(value = {"org.aurora"})
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

@ComponentScan 中的路径最好放在最大的,这样 config 类也能扫描到,否则你可能会发现自己的部分类配置了但是不起作用。

上方 @EntityScan(“org.aurora.entity”) 也可以加入到 spring-boot 配置文件中 而不写在文件里
例如:
在spring-boot 的 application.properties 或者 applicaiton.yml 中如下:
两种文件仅仅是排版格式不同而已,值一致
mybatis-plus 配置中,这里是 yml 如下:

mybatis-plus:
# mybaits 和mybaits-plus 都可以使用的xml 文件类的扫描加载路径
  mapper-locations: classpath:mapper/*Mapper.xml
# 上面的 EntityScan 可以替代,也可以写在这里
  typeAliasesPackage: org.aurora.entity
  • 1
  • 2
  • 3
  • 4
  • 5

properties类文件可以如下参考

# mybaits 和mybaits-plus 都可以使用的xml 文件类的扫描加载路径
mybatis-plus.mapper-locations = classpath:mapper/*Mapper.xml

# 上面的 EntityScan 可以替代,也可以写在这里
mybatis-plus.typeAliasesPackage= org.aurora.entity
  • 1
  • 2
  • 3
  • 4
  • 5

mapper-locations:classpath: 后为路径,可以理解为这里扫描 resources 下一个叫 mapper 的文件加里面 所有以 Mapper为文件名后缀的 xml 文件。

五、一般实体类定义

(在上面定义的实体类扫描路径包下创建)
以下所有注解均来源于mybaits-plus 以及 lombok

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 lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@TableName("t_person")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PersonEntity {

    @TableId(type = IdType.AUTO)
    private Long id;

    protected boolean flag;

    @TableField(value="create_time")
    protected Date createTime;

    @TableField(value = "person_name")
    private String personName;

    @TableField(value = "person_id")
    private String personId;

    @TableField(value = "person_pre")
    private String personPre;
}

  • 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

@Data
@NoArgsConstructor
@AllArgsConstructor
为lombok 注解用于简化 get set 以及构造方法等,可以使用一般的 get set 构建函数替代而不使用注解

@TableId
用于指定当前表的主键Id 如果自己设置了自增,不要忘了在建表时也设置主键自增否则会出现保存失败的情况

@TableName
指定当前表的表名

@TableField
指定当前属性在表中的字段名称
其中 flag 字段没有指定,可以认为单个单词时不用指定 table_field 默认使用属性名。

六、建立实体对应的Mapper 接口类 (dao 层)

(在上面指定的Mapper 扫描路径包下定义)

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.aurora.entity.PersonEntity;
import org.springframework.stereotype.Repository;

// 定义为持久层 数据库交互
@Repository
public interface PersonMapper extends BaseMapper<PersonEntity> {
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

是的 只需要这一点就可以了 这样 Mybaits 就提供了 PersonEntity 对应表的基本查询的所有方法,当然也可以像 mybatis 一样继续定义抽象方法,然后**在 resources 下的 mapper 包内添加对应 Mapper.xml 文件的SQL实现

七、Mapper 接口类的实际使用

在某一Service 中我可以如下定义

基本新增数据
import org.aurora.mapper.PersonMapper;
import org.aurora.entity.PersonEntity;
import org.aurora.service.PersonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@Slf4j
public class PersonServiceImpl implements PersonService {

    @Autowired
    private PersonMapper personMapper;

    @Override
    public void test() {

        PersonEntity personEntity = new PersonEntity();
        personEntity.setFlag(true);
        personEntity.setCreateTime(new Date());
        personEntity.setPersonId("*************");
        personEntity.setPersonName("jack");
        personEntity.setPersonPre("king");

        personMapper.insert(personEntity);
    }
}
  • 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

这是接口类 继承 BaseMapper<**Entity> 后提供的基本方法,只需要实体即可。
在这里插入图片描述

基本查询

继承 baseMapper 后即提供以下查询方法
在这里插入图片描述
selectByMap
入参为普通的 Map 其中 map 的key 需要放入实际表的字段名例如上面的(“person_name”), value 是某一个字段等于的值,相当于普通的条件查询。

selectCount
该方法为条件下计算总数
入参为 wrapper 类。wrapper 是mybaits-plus 的条件包装类,暂时可以当作Map 但是比 Map 更强大,提供了大于,等于,小于,like 等等,方法介绍完成后下面做具体说明。

selectList
查询满足某些条件的实体集合。

selectPage
查询满足某些条件的实体集合。同时支持分页,可以放入分页对象,自动完成分页查询。
分页下面与 wrapper 同时介绍

selectBatchIds
查询某一个id 集合下的所有实体。

selectById
通过主键查询

selectMaps
获取的结果转为 Map 的集合,可以用于单独几个字段或自定义结果查询。

      QueryWrapper<XxxxEntity> query = new QueryWrapper<>();
      query.like("name", "xxx").lt("age", 45);
      query.select("name", "age");
      List<Map<String, Object>> maps = mapper.selectMaps(query);
      // select("name", "age") 中指定要查询的列
  • 1
  • 2
  • 3
  • 4
  • 5

selectMapsPage
与上面比多了分页而已

selectObjs
同样的返回自定义结果集合,但是只有一列,多列的话可以使用selectMaps
例如:

        List<Object> resultList = mapper.selectObjs(new LambdaQueryWrapper<XxxxxEntity>()
                .eq(XxxxxEntity::getId, id)
                .eq(XxxxxEntity::getFlag, 1)
                .select(XxxxxEntity::getName));
// 以上的 select() 内指定了返回的结果字段名, 我这里相当于SQL:
// select name from XxxxxEntity(中的@tableName的表名) where id = xx, flag = 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这里的 LambdaQueryWrapper 也可以使用普通的 QueryWrapper,如果是 普通 QueryWrapper ,入参 column 那一列要给字符串的列名,是不能直接使用get一类的

selectOne
查询某些条件下唯一的实体

Wrapper 介绍 以及分页的基本使用

查询时使用 QueryWrapper
在这里插入图片描述
在这里插入图片描述
可以看的出wrapper 提供了很多包装功能,其中入参的 column 为列名Object 即为值condition当前语句加入实际查询语句的条件可以如下理解:

即最简单的我们某一个值不存在时某一句是不需要加入的,condition 就完成了整个封装过程减少了 if 的判断

eq: 相等
in: 一般的 in 条件
ge: 大于等于
gt: 大于
le: 小于等于
lt: 小于
between : 某一列 在某两个值之间
or: 或者

以及排序
在这里插入图片描述
like 模糊查询:
在这里插入图片描述
groupBy:
在这里插入图片描述
haveing:
在这里插入图片描述

一般的使用可以如下参考:

在这里插入图片描述

LambdaQueryWrapper

在这里插入图片描述
可以直接写入,省去手动书写字段名的过程,同样的还有 LambdaUpdateWrapper 用于更新操作

分页查询

示例:
注意Page的来源 也是mybatis-plus 不要用其他的,内部已经提供了总页数,总数,当前页,页容量,

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

@Service
@Slf4j
public class PersonServiceImpl implements PersonService {

    @Autowired
    private PersonMapper personMapper;

    @Override
    public void test() {
        String personName = null;

        Page<PersonEntity> page = new Page<>();
        // 查询的当前页码  第一页
        page.setCurrent(1);
        // 查询条数
        page.setSize(10);

        QueryWrapper<PersonEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flag", true);
        queryWrapper.eq(StringUtils.isNotEmpty(personName), "person_name", personName);
        queryWrapper.like("person_id", "4567");

        Page<PersonEntity> pageList = personMapper.selectPage(page, queryWrapper);
    }
}
  • 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

在这里插入图片描述

更新操作 updateWrapper

当使用更新时使用 updateWrapper
但与 queryWrapper 不同的是有 set 方法,即更新某一个字段的值
同样存在 condition 的用法,免去 if 的书写。
在这里插入图片描述
例如:
在这里插入图片描述
可以看的出可以直接将实体放入后自动通过Id 更新,也可以将wrapper 放入
第一个方法中的entity 可以不放入填写 null,则会根据 wrapper 中的条件更新所有符合条件的数据

删除

同样的删除也使用 updateWrapper
方法见名知意,都很简单。
在这里插入图片描述

到此所有的基本方法基本都可以无代码自动支持了!
不得不说,真的十分简化操作!

连表查询-连表分页 注解+sql实现

首先需要在 mapper 中额外定义抽象方法

下面第一个为分页,第二个为不分页

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

@Repository
public interface XxxxxMapper  extends BaseMapper<XxxxxEntity> {

    @Select("SELECT r.id, r.dept_id, r.person_id," +
            "s.secret_name, t.state, f.error  FROM t_person AS r "
            + " LEFT JOIN t_secret AS s ON r.id = s.per_id "
            + " LEFT JOIN t_xxxx AS f ON r.id = f.id "
            + " LEFT JOIN t_xxxxxxxx AS t ON f.flow_id = t.id "
            + " ${ew.customSqlSegment}")
    IPage<XxxxxxDTO> getListPageByConditions(IPage<XxxxxxDTO> pageDtoIPage, @Param("ew") Wrapper wrapper);

    @Select("SELECT r.id, r.dept_id, r.person_id," +
            "s.secret_name, t.state, f.error  FROM t_person AS r "
            + " LEFT JOIN t_secret AS s ON r.id = s.per_id "
            + " LEFT JOIN t_xxxx AS f ON r.id = f.id "
            + " LEFT JOIN t_xxxxxxxx AS t ON f.flow_id = t.id "
            + " ${ew.customSqlSegment}")
    XxxxxxDTO getListByConditions(@Param("ew") Wrapper wrapper);
}
  • 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

解读
第一个方法 getListPageByConditions 的分页方法需要我们将 mybatis-plus 的分页对象作为入参传入,外面调用时记得指定分页的当前页码以及页容量

其他的条件可以通过 queryWrapper 对象传入。
ew.customSqlSegment: ew 为别名 用于识别wrapper 对象,customSqlSegment 为queryWrapper 中的 方法
在这里插入图片描述
customSqlSegment 应该是用于获取queryWrapper 构建完成的 SQL 语句,所以在实际queryWrapper 时指定的列名也要用 表别名之类的指定才行
类似于:
在这里插入图片描述
这里查询出的字段名可以和对应实体定义的属性名一致即可,最终返回时会自动匹配列名。

例如上面查询了 secret_name 但是实体中我定义的是这样

    @TableField(value = "secret_name")
    private String secretName;
  • 1
  • 2

那么返回的自定义类中也使用 secretName 即可。

其他内容后续不定期继续加入,都在同一专题下

八、连表查询方式 (AI生成答案,注意识别)

Mybatis-Plus 提供了几种连表查询的实现方式,包括使用 LambdaQueryWrapper、QueryWrapper 以及直接编写 SQL 语句。下面通过一些示例来说明这些方法。

1. 使用 LambdaQueryWrapper

LambdaQueryWrapper 提供了一种类型安全的方式来构建查询条件,非常适合于进行连表查询。

假设我们有两个实体类,一个是 User,另一个是 Department,并且一个用户属于一个部门。

public class User {
    private Long userId;
    private String username;
    private Long departmentId;
    // 省略其他属性和getter/setter
}

public class Department {
    private Long departmentId;
    private String departmentName;
    // 省略其他属性和getter/setter
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
示例代码
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

List<User> userList = userMapper.selectList(
    Wrappers.lambdaQuery(User.class)
        .select(User::getUsername, User::getDepartmentId)
        .leftJoin(Department.class, User::getDepartmentId, Department::getDepartmentId)
        .like(User::getUsername, "test") // 假设查询用户名包含"test"的记录
        .apply("dept.department_name like {0}", "%技术%") // 这里假设dept是Department的别名,用于演示如何添加原生SQL条件
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
2. 使用 QueryWrapper

如果不喜欢使用 Lambda 表达式,可以使用 QueryWrapper,但相比LambdaQueryWrapper,它不那么类型安全。

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

List<User> userList = userMapper.selectList(
    new QueryWrapper<User>()
        .select("username", "department_id")
        .leftJoin("department", "user.department_id=department.department_id")
        .like("username", "test")
        .apply("department.department_name like {0}", "%技术%")
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
3. 使用自定义 SQL

对于更复杂的连表查询,可以直接在 Mapper 接口定义方法,并在对应的 XML 文件中编写 SQL。

Mapper 接口

public interface UserMapper extends BaseMapper<User> {
    List<User> selectUsersWithDepartment(String username);
}
  • 1
  • 2
  • 3

UserMapper.xml

<mapper namespace="你的全限定Mapper接口名">
    <select id="selectUsersWithDepartment" resultType="你的User实体类全限定名">
        SELECT u.*, d.department_name 
        FROM user u 
        LEFT JOIN department d ON u.department_id = d.department_id
        WHERE u.username LIKE #{username}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

然后,你可以在服务层调用这个自定义方法进行查询。
以上就是 Mybatis-Plus 实现连表查询的几种常见方式。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/830392
推荐阅读
相关标签
  

闽ICP备14008679号