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

 更新时间:2026年04月27日 08:35:59   作者:小裕哥略帅  
本文档详细介绍基于MyBatis-Plus框架实现的跨表查询分页功能,以供应商物料查询为例,展示如何通过多表关联查询并返回标准分页对象的技术实现方案

1. 概述

本文档详细介绍基于MyBatis-Plus框架实现的跨表查询分页功能。以供应商物料查询为例,展示如何通过多表关联查询并返回标准分页对象的技术实现方案。

2. 技术栈

ORM框架: MyBatis-Plus

数据库: MySQL(使用LIMIT进行分页)

分页组件: MyBatis-Plus Page对象

架构模式: Repository + Mapper + XML三层架构

3. 核心实现原理

3.1 分页策略

采用手动分页方式,分为两步执行:

查询总数: 执行COUNT查询获取符合条件的总记录数

查询数据: 根据偏移量(offset)和页大小(size)查询具体数据

3.2 为什么选择手动分页

跨表查询涉及LEFT JOIN,MyBatis-Plus自动分页可能存在性能问题

可以精确控制SQL语句,优化查询性能

支持复杂的动态条件拼接

4. 代码实现详解

4.1 参数对象设计

SupplierIdParam.java - 查询参数封装

@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;                   // 定价类型
    // ... 其他字段
}

关键点:

继承PageQueryParam,包含currentPage和pageSize分页参数

支持多维度动态查询条件

使用包装类型,便于判断参数是否为空

4.2 领域对象设计

SupplierMaterialDO.java - 供应商物料实体

@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.java

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

实现要点:

  • 分离计数查询: 单独执行COUNT查询,避免查询不必要的数据列
  • 计算偏移量: 使用page.offset()方法自动计算OFFSET值
  • 空值保护: 检查查询结果是否为空,避免设置null集合
  • 租户隔离: 所有查询都携带tenantId,实现多租户数据隔离

4.4 Mapper接口定义

SupplierMaterialMapper.java

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

设计说明:

  • 使用@Param注解明确参数名称,便于XML中引用
  • 将offset和size作为独立参数传递,提高SQL可读性
  • 返回类型分别为Long和List<SupplierMaterialDO>

4.5 MyBatis XML实现

SupplierMaterialMapper.xml

总数查询SQL

<select id="queryMaterialsBySupplierIdCount" resultType="java.lang.Long">
    SELECT count(*) AS total
    FROM t_supplier_material tsm
    LEFT JOIN t_material tm ON tsm.material_id = tm.id
    WHERE tsm.delete_flag = '0'
    AND tsm.tenant_id = #{tenantId}
    <if test="param.supplierId != null and param.supplierId != ''">
        AND supplier_id = #{param.supplierId}
    </if>
    <if test="param.materialCategoryExternalCode != null and param.materialCategoryExternalCode != ''">
        AND tsm.material_category_external_code LIKE CONCAT('%', #{param.materialCategoryExternalCode}, '%')
    </if>
    <if test="param.materialCategoryName != null and param.materialCategoryName != ''">
        AND tsm.material_category_name LIKE CONCAT('%', #{param.materialCategoryName}, '%')
    </if>
    <if test="param.materialName != null and param.materialName != ''">
        AND tsm.name LIKE CONCAT('%', #{param.materialName}, '%')
    </if>
    <if test="param.materialExternalCode != null and param.materialExternalCode != ''">
        AND tsm.external_code LIKE CONCAT('%', #{param.materialExternalCode}, '%')
    </if>
    <if test="param.materialStatus != null and param.materialStatus != ''">
        AND tm.status = #{param.materialStatus}
    </if>
    <if test="param.pricingType != null and param.pricingType != ''">
        AND tm.pricing_type = #{param.pricingType}
    </if>
</select>

分页数据查询SQL

<select id="queryMaterialsBySupplierId"
        resultType="com.mdgyl.hussar.basic.supplier.masterdata.domain.SupplierMaterialDO">
    SELECT tsm.*
    FROM t_supplier_material tsm
    LEFT JOIN t_material tm ON tsm.material_id = tm.id
    WHERE tsm.delete_flag = '0'
    AND tsm.tenant_id = #{tenantId}
    <!-- 动态条件与COUNT查询保持一致 -->
    <if test="param.supplierId != null and param.supplierId != ''">
        AND supplier_id = #{param.supplierId}
    </if>
    <if test="param.materialCategoryExternalCode != null and param.materialCategoryExternalCode != ''">
        AND tsm.material_category_external_code LIKE CONCAT('%', #{param.materialCategoryExternalCode}, '%')
    </if>
    <!-- ... 其他动态条件 ... -->
    ORDER BY tsm.id DESC
    LIMIT #{offset}, #{size}
</select>

SQL编写要点:

  • 表别名规范: 使用简短且有意义的别名(如tsm、tm)
  • 动态条件: 使用<if>标签实现条件可选,确保COUNT和DATA查询条件一致
  • 模糊查询: 使用CONCAT('%', value, '%')实现LIKE模糊匹配
  • 软删除过滤: 始终添加delete_flag = '0'条件
  • 排序规则: 使用ORDER BY id DESC保证数据稳定性
  • LIMIT分页: 使用LIMIT #{offset}, #{size}实现物理分页

到此这篇关于MyBatis-Plus实现跨表查询并返回分页的文章就介绍到这了,更多相关MyBatis-Plus跨表查询分页内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决idea配置Tomcat Deployment没有artifact选项的问题

    解决idea配置Tomcat Deployment没有artifact选项的问题

    今天在配置的时候tomcat deployment中却找不到artifact,没有artifact就不能打成war包上传到服务器了,那么怎么解决没有artifact选项的问题呢,今天通过本文给大家分享idea配置Tomcat Deployment没有artifact选项的解决方案,一起看看吧
    2023-10-10
  • Java http请求封装工具类代码实例

    Java http请求封装工具类代码实例

    这篇文章主要介绍了Java http请求封装工具类代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • 200行Java代码编写一个计算器程序

    200行Java代码编写一个计算器程序

    本篇文章给大家分享的只用200行java代码,实现一个计算器程序,不仅能够计算加减乘除,还能够匹配小括号。实现代码超简单,需要的朋友参考下吧
    2017-12-12
  • Java+Selenium实现控制浏览器的启动选项Options

    Java+Selenium实现控制浏览器的启动选项Options

    这篇文章主要为大家详细介绍了如何使用java代码利用selenium控制浏览器的启动选项Options的代码操作,文中的示例代码讲解详细,感兴趣的可以了解一下
    2023-01-01
  • Java基于代理模式解决红酒经销问题详解

    Java基于代理模式解决红酒经销问题详解

    这篇文章主要介绍了Java基于代理模式解决红酒经销问题,详细描述了代理模式的概念、原理并结合实例形式分析了java基于代理模式解决红酒经销问题的相关步骤、实现方法与操作注意事项,需要的朋友可以参考下
    2018-04-04
  • Java案例分享-集合嵌套

    Java案例分享-集合嵌套

    这篇文章主要介绍了Java案例分享-集合嵌套,通过案例创建一个ArrayList集合,存储三个元素,每一个元素都是HashMap,每一个HashMap的键和值都是String,并遍历,实际操作内容需要的小伙伴可以参考一下
    2022-04-04
  • IntelliJ IDEA修改新建文件自动生成注释的user名

    IntelliJ IDEA修改新建文件自动生成注释的user名

    今天小编就为大家分享一篇关于IntelliJ IDEA修改新建文件自动生成注释的user名,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • Java中驼峰命名与下划线命名相互转换

    Java中驼峰命名与下划线命名相互转换

    这篇文章主要介绍了Java中驼峰命名与下划线命名相互转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Java一维数组和二维数组元素默认初始化值的判断方式

    Java一维数组和二维数组元素默认初始化值的判断方式

    这篇文章主要介绍了Java一维数组和二维数组元素默认初始化值的判断方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • 剑指Offer之Java算法习题精讲求和篇

    剑指Offer之Java算法习题精讲求和篇

    跟着思路走,之后从简单题入手,反复去看,做过之后可能会忘记,之后再做一次,记不住就反复做,反复寻求思路和规律,慢慢积累就会发现质的变化
    2022-03-03

最新评论