递归和循环的优化

(一)场景描述

在电子商城项目中,我们会有一个获取目录的查询,目录下面有子目录。在后台的时候,我们怎样获取数据库中已经设计好的目录呢?

首先,面对一个需求,我们想的是,要将这个需求的基本功能进行实现,然后再想优化的事,一般不会立马想到最优方案,当然久经沙场用于丰富的实战经验的将军除外,像我们这些初出茅庐的小兵,只能先填饱肚子,然后再思考怎样优化功能…哈哈,废话,不多说了。

(二)数据库表设计

递归和循环的优化_第1张图片
pid是父目录的id,当pid为0时,表示为顶级目录。

(三)代码实现

mapper层这些,这里就不再进行赘述了…,这里只展示业务层的代码

  1. 递归实现
    @Override
    public List treeData() {
        return treeDataRecursion(0L);
    }
    
   /**
     * 获取商品的目录结构,
     *      目前实现方式有两种:
     *          其一:使用递归的方式
     *                  通过递归调用,获取所有的子目录,将所有的子目录存入在集合中,
     *                  递归的出口就是当前的子目录集合内为空,及当前目录没有儿子了
     *
     *                  但是递归调用的性能很差,会每递归依次都会发送很多sql,容易给服务器造成很大的压力,用户直观的体验就是系统反应迟缓
     */
    //首先获取所有的儿子
    public List getAllChildren(Long pid){
        Wrapper wrapper = new EntityWrapper<>();
        wrapper.eq("pid",pid);  //此处使用pid,是因为在mapper.xml内,进行另取别名
        return productTypeMapper.selectList(wrapper);
    }

    public List treeDataRecursion(Long pid){
        //首先获取所有的儿子
        List allChildren = getAllChildren(pid);

        //递归的出口,当前集合下面没有儿子
        if(allChildren.size()==0 || allChildren==null){
            return null;
        }
        
        //递归调用,获取当前目录下的子目录
        for (ProductType current : allChildren){
            //获取当前目录的儿子
            List productTypes = treeDataRecursion(current.getId());
            //将儿子设置给当前目录
            current.setChildren(productTypes);
        }

        return allChildren;
    }`
  1. 循环实现
    @Override
    public List treeData() {
        return treeDataLoop();
    }

    /**
     * 获取商品的目录结构,
     *         其二:使用循环的方式
     *                  只发送一条sql,将所有的pid查询到内存,然后再内存中对目录进行组装
     */
    public List treeDataLoop(){

        //1.  只 发送一条sql语句,获取所有的目录 ,此时所有的目录已经存储在内存中
        List allProductType = productTypeMapper.selectList(null);

        //3.  使用集合存放所有的顶级目录
        List first = new ArrayList<>();

        //4.  使用Map,存放所有的对象,包括顶级目录
        Map map = new HashMap<>();
        for (ProductType productType: allProductType) {
            map.put(productType.getId(),productType);
        }

        //2.  对所有的目录进行组装,组装父子关系
        for (ProductType productType: allProductType) {
            //根据数据库中的设计,当目录的pid为0,说明此目录是一个顶级目录,
            if(productType.getPid() == 0){
                //将顶级目录存放到事先准备好的list中
                first.add(productType);
            }else{
                //非顶级目录,需要进行父子关系的组装

                //获取父级目录 ,使用之前的map,避免循环的嵌套使用
                ProductType parentPt = null;
                parentPt = map.get(productType.getPid());

                //将当前的目录添加到父级目录内,作为儿子存在
                parentPt.getChildren().add(productType);
            }
        }

        //5.  最后直接返回顶级目录就可以,因为已经进行了父子的组装,找到父亲,就能找到儿子
        return first;
    }

考虑代码的重构和复用、注重性能的代码才是优质的代码

不断提升吧…共勉

你可能感兴趣的:(性能优化)