当前位置: 首页 > news >正文

mybaits跨表查询返回分页

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


4.5.1 总数查询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>

4.5.2 分页数据查询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}实现物理分页

http://www.cnnetsun.cn/news/2093069.html

相关文章:

  • MarkDownload 终极指南:如何快速将网页转为 Markdown 文件
  • 中望CAD2026机械版:将点坐标批量导入
  • 论智能体知识工程的局限与进化方向:从Karpathy的Wiki系统到下一代记忆架构
  • lang属性怎么设语言_HTML文档语言声明方法【操作】
  • 微软开源RD-Agent:运维监控的深度诊断利器与实战配置指南
  • 告别毕设焦虑!百考通AI助你高效搞定毕业论文
  • 音频频谱可视化分析:5个关键场景中Spek如何提升你的音频工作流 [特殊字符]
  • WeChatMsg终极教程:如何永久保存并智能分析你的微信聊天记录
  • 霍尼韦尔宣布出售仓储与工作流解决方案业务 | 美通社头条
  • 终极M3U8视频下载指南:告别命令行,拥抱图形化操作
  • FAPROTAX 1.2.10数据库升级:微生物功能预测如何实现从“猜“到“知“的跨越?
  • Python的__enter__方法返回上下文管理器自身与with语句的嵌套支持
  • 为什么你的C++26合约永远不触发?揭秘__builtin_contract_violation底层汇编指令生成逻辑(含x86-64/AArch64双平台反汇编对照)
  • 机器学习项目中SQLite与DBM数据管理实战
  • 2026学Java好不好找工作?揭秘行业真相与我的亲身经历
  • 如何高效实现多用户通知系统而不造成数据库冗余
  • 机器学习参数与超参数:核心概念与实践指南
  • Arm架构寄存器编程与定时器控制详解
  • 算子数学|独立完整学科章节(百条原创公式· ROOT传世定稿)
  • 电影票特惠出票和快速出票到底什么逻辑? 看完就懂!
  • 量子纠错解码器:BP算法与光束搜索技术解析
  • 【2026年最新600套毕设项目分享】微信小程序的校园跑腿系统(30164)
  • C工程师年薪跃迁关键帧:掌握这11个C11/C17内存模型原子操作边界案例,直通华为/寒武纪安全岗终面
  • 2025届必备的十大降重复率方案推荐榜单
  • Claw-R1开源硬件平台:如何为LLM智能体构建物理交互能力
  • Python 协程任务异常处理机制
  • LiveDraw:终极实时屏幕标注工具完全指南
  • DeepSeek V4降AI痕迹避坑指南,2026年4月8个常见错误
  • 实用云手机 贴合日常需求
  • Arm SVE2指令集:矩阵运算与密码学加速实战解析