Mybatis如何多表之间的分页查询

Mybatis 多表之间的分页查询

分页查询

  • 什么是分页?
    分页,是一种将所有数据分段展示给用户的技术。用户每次看到的不是全部数据,而是其中的一部分,如果在其中没有找到自习自己想要的内容,用户可以通过制定页码或是翻页的方式转换可见内容,直到找到自己想要的内容为止。其实这和我们阅读书籍很类似。

  • 分页的意义
    (1). 数据方面的原因,减少数据库压力
    (2). 增强用户使用体验需要


场景

今天早上同事在和前端对接得时候出现了一点分歧原因是因为页面上有一个布局上需要进行分页,但是后端接口返回的数据中没有allPage、allCount两个参数导致前端没法分页。后端同事说无法分页是由于他的后端查询sql是一个复杂sql,没办法用常规的分页来做。

但其实mybatis是是支持多表复杂sql的分页的,告知同事后以将该问题解决。同时在此记录网上有遇到相同问题的小伙伴可以参考借鉴。


解决办法

利用mybatis的PageResult可以处理这个问题,PageResult根据使用使用者的req中的pageIndex、pageSize封装进mybatis自定的Page对象作为参数传入就能对查询的结果自动分页。

PageResult:

public class PageResult<T> implements Serializable {
    private long allCount;
    private long allPages;
    private long pageNum;
    private long pageSize;
    private List<T> dataItems;

    public <R> PageResult<R> convert(Function<? super T, ? extends R> mapper) {
        List<R> collect = (List)this.dataItems.stream().map(mapper).collect(Collectors.toList());
        PageResult<R> result = new PageResult();
        result.setAllCount(this.getAllCount());
        result.setAllPages(this.allPages);
        result.setPageNum(this.pageNum);
        result.setPageSize(this.pageSize);
        result.setDataItems(collect);
        return result;
    }
	    ......
}		

如何使用

只要我们在自定义复杂sql的时候灵活运用,多表分页查询也能达到很好的效果:

  • 自定义Mapper的返回值接收用PageResult
  • 查询条件必须带Page参数

DEMO

mapper.java写法:

    /**
     * 分页查询
     * @param configReq   条件入参
     * @param page        分页参数 : 必传,里面是pageIndex和pageSize
     * @param frequency   查询条件
     * @return            分页后的结果
     */
    PageResult<ConfigBo> listConfig(@Param("configReq") ConfigReq configReq, Page page,@Param("frequency") Integer frequency);

mapper.xml写法:

    <select id="listConfig" parameterType="com.hikcreate.hdsp.service.supervise.infra.model.request.ConfigReq"
            resultType="com.hikcreate.hdsp.service.supervise.infra.model.bo.ConfigBo">
        select 
            config.id AS configId,
            config.supervise_name AS superviseName,
            type.type_name AS typeName,
            rel.model_id AS modelId,
            config.enable_state AS enableState,
            type.type_code AS typeCode
            from supervise_config config
            left join supervise_business_type type on config.business_type_code = type.type_code
            left join supervise_model_dept_rel rel on config.id = rel.supervise_config_id
            left join supervise_rule_config rule on config.id = rule.supervise_config_id where 1 = 1
            <if test="configReq.superviseName != null and configReq.superviseName != ''" >
                    and config.supervise_name = #{configReq.superviseName}
                </if>
            <if test="configReq.typeCode != null and configReq.typeCode != ''" >
                    and type.type_code = #{configReq.typeCode}
                </if>
            <if test="frequency != null " >
                    and rule.frequency = #{frequency}
            </if>
    </select>

mapper.java注意入参需要有Page page这个参数,接收返回值时需要用PageResult进行接收,mapper.xml中的写法就和正常写法一致,因为PageResult在封装返回值时候会自动将分页查询结果的参数封装进返回结果之中

效果

在这里插入图片描述

总结

只要思想不滑坡,困难总比办法多。

### MyBatis Plus 实现分页查询 为了实现MyBatis Plus的分页查询,需先确保已配置`PaginationInnerInterceptor`插件来支持分页功能[^1]。 #### 配置分页插件 在Spring Boot项目中,可以通过如下方式注册分页拦截器: ```java import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } } ``` #### 定义实体类映射关系 假设存在两个:`users` 和 `products`。其中`users` 存储用户信息而`products` 存储商品详情,并且两者之间有一对的关系(即一个用户可以关联个产品)。此时应该创建相应的Java实体类并建立它们之间的联系。 对于User.java: ```java @Data @NoArgsConstructor @AllArgsConstructor @TableName("users") public class User implements Serializable { private static final long serialVersionUID = 1L; /** * 用户ID */ @TableId(value="id", type= IdType.AUTO) private Integer id; /** * 用户名 */ private String username; // ...其他字段... /** * 关联的产品列 (一对) */ @TableField(exist=false) private List<Product> productList; } ``` 以及Product.java: ```java @Data @NoArgsConstructor @AllArgsConstructor @TableName("product") public class Product implements Serializable { private static final long serialVersionUID = 1L; /** * 商品ID */ @TableId(value="id", type= IdType.AUTO) private Integer id; /** * 所属用户的ID */ private Integer userId; /** * 商品名称 */ private String name; //...其他字段... } ``` #### 编写Mapper接口 接下来编写对应的Mapper接口,在这里我们将使用到`BaseMapper<T>` 接口所提供的基本CRUD方法之外还需要自定义一些SQL语句来进行复杂的操作比如联合查询等。 针对上述提到的例子来说就是分别构建`UserMapper` 及其内部的方法用于获取带有分页参数的结果集;同样也要为`ProductMapper` 提供相应的能力以便于后续处理逻辑调用。 关于`UserMapper` 的部分可参照下面的形式: ```java @Mapper public interface UserMapper extends BaseMapper<User> { /** * 根据颜色筛选带分页条件下的用户数据 * * @param page 分页对象 * @return 返回符合条件的用户页面化结果 */ IPage<Users> selectPageByColor(@Param("page") Page<Users> page); /** * 获取指定用户及其对应的商品列 * * @param uid 用户唯一标识符 * @return 包含该用户所拥有的全部产品的集合 */ @Select("<script>" + "SELECT u.*, p.* FROM users u LEFT JOIN product p ON u.id=p.user_id WHERE u.id=#{uid}" + "</script>") List<Map<String, Object>> getUserWithProducts(@Param("uid") Long uid); } ``` 而对于`ProductMapper`, 如果只需要简单的基于单个的操作,则可以直接继承`BaseMapper<Product>` 即可满足需求。 最后需要注意的是当涉及到跨查询时最好采用内连接(`INNER JOIN`) 或者左外连接 (`LEFT OUTER JOIN`) 来保证最终得到的数据准确性[^2].
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值