根据一个类里的某个字段,进行分类(大数据量)

版权声明:转发请注明链接和出处,靴靴 https://blog.csdn.net/weixin_43525116/article/details/84979343

应用情景:货物类需要按照批次分类,以树列表形式展示

  1. 父列表展示每个批次中任意的一个货物;
  2. 点击该父列表中的某行,下拉展示子列表,子列表展示该行同一批次的所有单号;

小白版解决方案:逻辑分页

先查询所有数据到内存,再从内存截取需要数据采用程序内部逻辑,该方案属于前台分页。

  1. 查询出所有货物的数据
  2. 使用Map,根据批次batchFlag字段,对货物分组
        List<BillVo> list = billDao.searchBillList(billSo);
        Map<String, List<BillVo>> map = new HashMap<>();
        for (BillVo vo: list) {
            String batchFlag = vo.getBatchFlag();
            if (map.containsKey(batchFlag)) {
                map.get(batchFlag).add(vo);
            } else {
                List<BillVo> tempList = new ArrayList<>();
                tempList.add(vo);
                map.put(batchFlag,tempList);
            }
        }
  1. 遍历每个批次的List,提取出父列表,并展示该批次的总数和总重量
        // 遍历每个批次的List,提取出父菜单List
        List<BillVo> billVos = new ArrayList<>();
        for (String batchFlag : map.keySet()) {
            List<BillVo> sameBatchFlagList = map.get(batchFlag);
            //计算总重量
            Double sumWeight = 0.0d;
            if(CollectionUtils.isNotEmpty(sameBatchFlagList)){
                for(BillVo vo : sameBatchFlagList){
                    sumWeight = DecimalUtil.add(sumWeight,vo.getChargedWeight())
                            .doubleValue();
                }
            }
            // 获取第一个作为父菜单展示
            BillVo billVo = sameBatchFlagList.get(0);
            billVo.setBatchSize(Integer.toString(sameBatchFlagList.size()));
            billVo.setSumWeight(sumWeight));
            billVos.add(billVo);
        }
  1. 最终使用 PageList 类封装,分页数据。

改进版方案:物理分页(推荐)

在数据库执行查询时(实现分页查询),查询需要的数据依赖数据库SQL语句,属于后台分页。

因为分类依据batch_flag字段没有添加索引,所以可以Group By batch_flag,有索引的字段sen_site_id,send_date 减少查询数量级,提高查询速度;

Mapper.xml 里的sql语句

    <select id="searchBillParentListOut" resultMap="billVoResultMap">
        SELECT t.send_site_id, t.send_date, t.batch_flag, COUNT(1) AS batch_size, SUM(charged_weight) AS sum_weight FROM gw_bill t
        <include refid="SO_Where_Clause"/>
        GROUP BY t.send_site_id, t.send_date, t.batch_flag
    </select>
    <sql id="SO_Where_Clause">
        <where>
            1=1
            <if test="id!=null">
                and t.ID=#{id}
            </if>
            <if test="sendDate!=null">
                and t.SEND_DATE = #{sendDate}
            </if>
            <if test="sendDateFrom!=null">
                and t.SEND_DATE<![CDATA[ >= ]]>#{sendDateFrom}
            </if>
            <if test="sendDateTo!=null">
                and t.SEND_DATE<![CDATA[ <= ]]>#{sendDateTo}
            </if>
            <if test="sendSiteId!=null">
                and t.SEND_SITE_ID=#{sendSiteId}
            </if>
            ...
        </where>
        <include refid="Common.Order_By_Clause"/>
    </sql>

分页查询
使用Spring-Mybatis结合,自动分页查询,Dao层从传参提取出分页参数,然后将分页参数传给Mybatis。(本文是比较浅显的实践,未说明Mybatis分页插件实现的原理)

Dao层
    // 父列表List,分页查询,按批次分组
    @Override
    public List<BillVo> searchBillParentListOut(BillSo so) {
        // 提取分页参数
        RowBounds rowBounds = getRowBounds(so);
        if (so.getLimit() == 0) {
            rowBounds = new RowBounds((so.getPageNumber() - 1) * so.getPageSize(), so.getPageSize());
        }
        try {
            // 执行BillMapper.xml里id为searchBillParentListOut的sql语句
            return sqlSessionTemplate.selectList("Bill.searchBillParentListOut", so, rowBounds);
        } catch (Exception e) {
            logger.warn(getStatementPrefix() + "error.getVOListBySo", e);
            throw new DAOException(e);
        }
    }

selectList方法的几种重载

  /**
   * 普通sql语句
   */
  public <E> List<E> selectList(String statement) {
    return this.sqlSessionProxy.<E> selectList(statement);
  }

  /**
   * sql语句,传入参数类So,where语句就可以使用搜索节点<include refid="SO_Where_Clause"/>
   */
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.sqlSessionProxy.<E> selectList(statement, parameter);
  }

  /**
   * sql语句,传入参数类So,分页参数,使用了SqlSession
   */
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    return this.sqlSessionProxy.<E> selectList(statement, parameter, rowBounds);
  }

子列表数据量不大,不需要分页,一般查询就好。

注意点

因为查出来的分页数据parentList是当前页的父列表数据,所以使用PageList类封装传给前台的时候,list总量setFullListSize()需要一个新的count sql语句,来查询父列表所有页的总数。

猜你喜欢

转载自blog.csdn.net/weixin_43525116/article/details/84979343