关于mybatis多表联查导致列表数据量异常的处理

关于mybatis多表联查导致列表数据量异常的处理

本文章的方法只是一种解决方法,不确定对数据查询速率或其他是否有影响,但是相比于把主表数据查询后再循环查询具体信息来说,查询次数大幅度降低。

问题解析

问题为:在一对多的关系中,使用多表联查,往往会查询出多于主表数量的数据,通过mybatis解析后,数据会进行合并,但是翻页查询结果中的 total 总数,是不会减少的,这样就导致分页查询时,获取到的总量与实际总量不匹配的问题。

解决方法

SQL

我们先看一下多表联查的SQL

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.bamboo.lims.mapper.TaskBillDetailMapper">

    <resultMap id="TaskBillDetail" type="com.bamboo.lims.entity.TaskBillDetail">
        <id property="id" column="id" jdbcType="VARCHAR"/>
        <result property="createTime" column="create_time"/>
        <result property="companyId" column="company_id"/>
        <result property="detectionPeriod" column="detection_period"/>
        <collection property="projectList" ofType="com.bamboo.lims.entity.TaskBillDetailProject">
            <id property="id" column="pid" jdbcType="VARCHAR"/>
            <result property="projectId" column="project_id"/>
            <association property="project" javaType="com.bamboo.lims.entity.BaseTestProject">
                <id property="id" column="project_id" jdbcType="VARCHAR"/>
                <result property="name" column="name" jdbcType="VARCHAR"/>
                <result property="encodingNumber" column="encoding_number" jdbcType="VARCHAR"/>
            </association>
        </collection>
    </resultMap>

    <sql id="sql_selectDetailList">
        FROM lims_task_bill_detail d
        LEFT JOIN lims_task_bill_detail_project p ON p.detail_id = d.id
        LEFT JOIN lims_base_test_project pr on pr.id = p.project_id
    </sql>

    <select id="selectDetailListPage" resultType="com.bamboo.lims.entity.TaskBillDetail">
        SELECT d.id
        <include refid="sql_selectDetailList"/>
        <where>
            ${ew.sqlSegment}
        </where>
    </select>

    <select id="selectDetailList" resultMap="TaskBillDetail">
        SELECT d.id, d.create_time, d.company_id, d.detection_period, p.id AS pid,
        p.project_id, pr.name, pr.encoding_number
        <include refid="sql_selectDetailList"/>
        <where>
            ${ew.sqlSegment}
        </where>
    </select>

</mapper>

通过编写 resultMap 结果集,我们能将查询的数据进行合并,
定义两格查询方法:

  • 多表联查,保留主表ID,进行条件查询,这里不只查询主表,而同样采用多表联查方式,是因为,这个查询方法是实际意义上的分页查询方法,同时带有对所有关联表进行条件查询的功能。
  • 多表联查,查询所有数据。这个查询,是我们写多表联查的真实目的,查询详细信息,并列表返回

Mapper

// 查询详细信息列表
List<TaskBillDetail> selectDetailList(@Param("ew") Wrapper<TaskBillDetail> queryWrapper);
// 查询详细信息列表分页数据(只获取主表ID),配合selectDetailList使用
IPage<TaskBillDetail> selectDetailListPage(IPage<TaskBillDetail> page, @Param("ew") Wrapper<TaskBill> queryWrapper);

注意这两个方法,一个用于分页,一个用于查询列表,参数与返回类型都不一样。

Service

	public IPage<TaskBillDetail> getDetailList(String page, String limit) {
		// 列表,用于存放本次分页获取到的列表数据的ID,为再次多表联查查询详情做准备
        List<String> ids = new ArrayList<>();
        // 分页获取实际意义上的主表分页
        IPage<TaskBillDetail> taskBillDetailIPage = buildPage(page, limit);
        QueryWrapper<TaskBill> queryWrapper = new QueryWrapper<>();
        queryWrapper.apply("1=1"); // 这里必须写,否则没有where条件会报错
        queryWrapper.groupBy("d.id"); // 先查询本页有哪些数据
        taskBillDetailIPage = mapper.selectDetailListPage(taskBillDetailIPage, queryWrapper);
        // 循环获取本次分页查询得到的ID
        for (TaskBillDetail record : taskBillDetailIPage.getRecords()) {
            ids.add(record.getId());
        }
        // 这里一定要判断数量,否则没有拿到ID列表会导致 in 条件失效
        if (ids.size() > 0) {
	        // 再根据本页的数据的ID列表获取本页具体数据
	        QueryWrapper<TaskBillDetail> wrapper = new QueryWrapper<>();
	        wrapper.in("d.id", ids);
	        List<TaskBillDetail> taskBillDetails = mapper.selectDetailList(wrapper);
	        // 设置数据到分页对象中
	        taskBillDetailIPage.setRecords(taskBillDetails);
        }
        return taskBillDetailIPage;
    }

这样一来,即获取到了真正的数量,有同时获取到了这4条数据的详细信息。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值