商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > MyBatis-Plus实现跨表查询并返回分页

MyBatis-Plus实现跨表查询并返回分页

  发布于2026-07-12 阅读(0)

扫一扫,手机访问

1. 概述

在数据库开发中,跨表查询和分页返回是最常见的需求之一。这篇文章就专门聊聊如何基于MyBatis-Plus框架,实现一个靠谱的跨表查询分页功能。我们会以供应商物料的实际查询场景为例,一步步拆解多表关联查询,并最终拿到一个标准的分页对象。

MyBatis-Plus实现跨表查询并返回分页

2. 技术栈

先简单交代一下我们用到的技术组件:

  • ORM框架:MyBatis-Plus
  • 数据库:MySQL(使用LIMIT进行分页)
  • 分页组件:MyBatis-Plus Page对象
  • 架构模式:Repository + Mapper + XML三层架构

3. 核心实现原理

3.1 分页策略

这里不搞什么玄乎的自动分页,我们走的是手动控制路线。整个过程分两步:

  • 查总数:先跑一个COUNT查询,拿到符合条件的数据总量。
  • 查数据:根据偏移量(offset)和页大小(size),精准捞取当前页的数据。

3.2 为什么选择手动分页

你可能要问了,MyBatis-Plus不是自带分页插件吗?为啥还自己动手?原因其实很简单:

  • 跨表查询往往涉及LEFT JOIN,如果让框架自动分页,生成的SQL有时并不高效,甚至可能漏数据。
  • 手动控制SQL,你就能对每一步的执行细节心里有数,优化起来也更直接。
  • 当查询条件复杂、动态拼接的情况多时,手动分页的灵活性和可控性就体现出来了。

4. 代码实现详解

4.1 参数对象设计

首先,我们需要一个参数对象来承载查询条件。它继承了PageQueryParam,这样就有了currentPagepageSize这两个核心分页参数。

@Getter
@Setter
@ToString
public class SupplierIdParam extends PageQueryParam {
    private Long tenantId;                        // 租户ID
    private Long supplierId;                      // 供应商ID
    private String materialCategoryExternalCode;  // 物料分类外部编码
    private String materialCategoryName;          // 物料分类名称
    private String materialName;                  // 物料名称
    private String materialExternalCode;          // 物料编码
    private String materialStatus;                // 物料状态
    private String pricingType;                   // 定价类型
    // ... 其他字段
}

设计这个对象时,有几点值得留意:

  • 继承设计非常实用,分页参数不用重复写。
  • 所有字段都支持多维度动态查询,条件可组合、可灵活增减。
  • 字段类型都用包装类,方便判断是否传参——这在动态SQL里是基础操作。

4.2 领域对象设计

接着是承载数据的实体,它映射到数据库的t_supplier_material表:

@Getter
@Setter
@TableName(value = "t_supplier_material", autoResultMap = true)
public class SupplierMaterialDO implements BaseEntity {
    private Long id;
    private Long tenantId;
    private Long supplierDataId;
    private Long materialCategoryId;
    private String materialCategoryExternalCode;
    private String materialCategoryName;
    private Long materialId;
    private String externalCode;
    private String name;
    // ... 其他字段
}

这里有两个细节:

  • @TableName里的autoResultMap = true,为复杂结果映射开了绿灯。
  • 实现了BaseEntity接口,保证了通用字段的统一管理。

4.3 Repository层实现

到了组织查询逻辑的环节,看SupplierMaterialRepository

@Repository
public class SupplierMaterialRepository extends HussarServiceImpl {
    @Resource
    private SupplierMaterialMapper supplierMaterialMapper;
    public Page queryMaterialsBySupplierId(SupplierIdParam param) {
        Long tenantId = param.getTenantId();
        // 第一步:查询总数
        Long total = supplierMaterialMapper.queryMaterialsBySupplierIdCount(param, tenantId);
        // 第二步:创建分页对象
        Page page = new Page<>(param.getCurrentPage(), param.getPageSize(), total);
        // 第三步:查询分页数据
        List supplierMaterialDOList = 
            supplierMaterialMapper.queryMaterialsBySupplierId(param, tenantId, page.offset(), page.getSize());
        // 第四步:设置结果集
        if (CollectionUtils.isNotEmpty(supplierMaterialDOList)) {
            page.setRecords(supplierMaterialDOList);
        }
        return page;
    }
}

实现要点其实很清晰:

  • 计数查询单独执行,不走数据查询的弯路,能有效提升性能。
  • page.offset()自动帮我们算出偏移量,省心不少。
  • 设置结果集前先判空,避免空指针这种低级问题。
  • 租户ID全程携带,多租户隔离的机制不能丢。

4.4 Mapper接口定义

数据访问层接口,定义了两个核心方法:

@Mapper
public interface SupplierMaterialMapper extends BaseMapper, HussarMapper {
    
    /**
     * 查询总数
     */
    Long queryMaterialsBySupplierIdCount(@Param("param") SupplierIdParam param, 
                                         @Param("tenantId") Long tenantId);
    
    /**
     * 查询分页数据
     */
    List queryMaterialsBySupplierId(@Param("param") SupplierIdParam param, 
                                                        @Param("tenantId") Long tenantId, 
                                                        @Param("offset") Long offset, 
                                                        @Param("size") Long size);
}

设计上,有几点值得注意:

  • @Param把参数名标清楚,XML里引用时一目了然。
  • 偏移量和页大小作为独立参数传递,SQL的意图更明确。
  • 返回类型一个是对应总数,一个是对应数据集,职责分明。

4.5 MyBatis XML实现

SQL部分,我们先看总数查询:

再看分页数据查询:

SQL编写上有几个关键点:

  • 表别名用tsmtm,简短又清晰。
  • 动态条件靠标签实现,而且COUNT和DATA查询的条件必须完全一致。
  • 模糊查询用CONCAT拼接,避免SQL注入风险。
  • 软删除条件delete_flag = '0'是硬性要求,不能漏。
  • 排序用ORDER BY id DESC,保证分页结果稳定。
  • 最后用LIMIT #{offset}, #{size}实现物理分页,简单直接。
本文转载于:https://www.jb51.net/program/3628827ub.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注