美文网首页Java 杂谈
B2B2B2C 电商系统首页导航优化

B2B2B2C 电商系统首页导航优化

作者: Java_or_PHP | 来源:发表于2018-05-11 10:22 被阅读84次
image.png

定位问题

  1. 日志里出现了几千次这样的sql
mapper.BrandMapper.findByClassId - ========>  Preparing: select brand_id, brand_name, brand_class, brand_pic, brand_sort, brand_recommend, store_id,brand_apply, class_id,is_del,create_time,update_time from shop_brand where class_id = ? and is_del = 0 and brand_apply = 1 order by brand_sort desc 

GoodsClassCustomMapper.findChild - ========>  Preparing: SELECT gc_id,gc_parent_id,gc_rel_gcid,gc_name,gc_pic,gc_sort,gc_show,gc_title,gc_keywords, gc_description,gc_idpath,gc_url,gc_adduser,gc_upuser,gc_advid,create_time, update_time , (select count(*) from shop_goods_class_custom s1 where s1.gc_parent_id=s.gc_id ) has_child FROM shop_goods_class_custom s where gc_parent_id = ? and gc_show=1 order by gc_sort DESC 

这肯定是循环执行了sql了。所以,需要找循环执行的地方。

  1. 通过全局搜索 findByClassIdfindChild 两个函数,且是循环执行的地方,发现可能是 Mapper 里出的问题:
    <resultMap id="BaseResultMap" type="com.leimingtech.core.entity.GoodsClass">
        <id column="gc_id" property="gcId" jdbcType="VARCHAR"/>
        <result column="gc_name" property="gcName" jdbcType="VARCHAR"/>
        <result column="gc_pic" property="gcpic" jdbcType="VARCHAR"/>
        <result column="type_id" property="typeId" jdbcType="VARCHAR"/>
        <result column="type_name" property="typename" jdbcType="VARCHAR"/>
        <result column="gc_parent_id" property="gcParentId" jdbcType="VARCHAR"/>
        <result column="gc_sort" property="gcSort" jdbcType="INTEGER"/>
        <result column="gc_show" property="gcshow" jdbcType="INTEGER"/>
        <result column="gc_title" property="gcTitle" jdbcType="VARCHAR"/>
        <result column="gc_keywords" property="gcKeywords" jdbcType="VARCHAR"/>
        <result column="gc_description" property="gcDescription" jdbcType="VARCHAR"/>
        <result column="gc_idpath" property="gcIdpath" jdbcType="VARCHAR"/>
        <result column="has_child" property="hasChild" jdbcType="INTEGER"/>
        <result column="expen_scale" property="expenScale" jdbcType="FLOAT"/>
        <result column="is_relate" property="isRelate" jdbcType="INTEGER"/>
        <result column="virtual_goods" property="virtualGoods" jdbcType="INTEGER"/>
        <result column="relation" property="relation" jdbcType="INTEGER"/>
        <collection property="classList" ofType="com.leimingtech.core.entity.GoodsClass"
                    column="gc_id" javaType="arraylist"
                    select="com.leimingtech.service.module.goods.dao.mapper.GoodsClassMapper.findChild">
        </collection>
        <collection property="brandList" ofType="com.leimingtech.core.entity.base.Brand" column="gc_id"
                    javaType="arrayList"
                    select="com.leimingtech.service.module.goods.dao.mapper.BrandMapper.findByClassId">
        </collection>
    </resultMap>

这个文件里,这两个sql是同时出现的,正好和日志里出现的模式一样。这样的文件有两个

C:\opt\zzwelfare\welfare-service\src\main\resources\com\leimingtech\service\module\goods\dao\mapper\GoodsClassCustomMapper.xml
C:\opt\zzwelfare\welfare-service\src\main\resources\com\leimingtech\service\module\goods\dao\mapper\GoodsClassMapper.xml
  1. GoodsClassCustomMapper使用了 BaseResultMap 的地方有:
     <!--递归查询所有分类-->
    <select id="findAllbyisshow" resultMap="BaseResultMap" parameterType="com.leimingtech.core.entity.GoodsClassCustom">
        SELECT
        <include refid="Base_Column_List" />,
        (select count(*) from shop_goods_class_custom s1 where s1.gc_parent_id=s.gc_id and s1.gc_show=#{gcshow}) has_child
        FROM shop_goods_class_custom s where gc_parent_id ='0'
        <if test="gcshow != null and gcshow != ''">
            and gc_show=#{gcshow}
        </if>
        order by gc_sort DESC
    </select>

注释里居然还写了递归查询所有分类

优化目标:去掉 mapper 里的循环查询

使用了 findAllbyisshow 的地方有:

welfare-api/src/main/java/com/leimingtech/extend/module/api/GoodsApi.java
welfare-front/src/main/java/com/leimingtech/front/module/tag/EgoodsClassCustomProductTag.java
welfare-front/src/main/java/com/leimingtech/front/module/tag/EgoodsClassProductTag.java
welfare-front/src/main/java/com/leimingtech/front/module/tag/GoodsClassCustomTag.java
welfare-front/src/main/java/com/leimingtech/front/module/tag/GoodsClassTag.java
welfare-h5/src/main/java/com/leimingtech/extend/module/h5/category/CategoryHtml5Action.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/dao/GoodsClassCustomDao.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/dao/GoodsClassDao.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/dao/impl/GoodsClassCustomDaoImpl.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/dao/impl/GoodsClassDaoImpl.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/dao/mapper/GoodsClassCustomMapper.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/dao/mapper/GoodsClassMapper.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/service/GoodsClassCustomService.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/service/GoodsClassService.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/service/impl/GoodsClassCustomServiceImpl.java
welfare-service/src/main/java/com/leimingtech/service/module/goods/service/impl/GoodsClassServiceImpl.java

总共这16个地方。首页,或者类似首页用的有:

  1. welfare-service/src/main/java/com/leimingtech/service/module/goods/service/GoodsClassCustomService.java
    /**
     * 查询所有的分类
     * @return
     */
    @Override
    public List<GoodsClassCustom> findAllbyisshow(GoodsClassCustom goodsClassCustom) {
        List<GoodsClassCustom> gclzs = null;
        if(JedisConfig.JEDIS_STATUS){
            ////需要安装redis
            Object obj = JedisUtils.getObject(JedisConfig.GCLZ_PREFIX + "goodsClassCustom");
            if(obj == null){
                gclzs = goodsClassCustomDao.findAllbyisshow(goodsClassCustom);
                //10分钟
                JedisUtils.setObject(JedisConfig.GCLZ_PREFIX + "goodsClassCustom", gclzs, JedisConfig.JEDIS_EXPIRE);
                log.debug(JedisConfig.GCLZ_PREFIX + "存入redis");
            }else{
                gclzs = (List<GoodsClassCustom>)obj;
                log.debug(JedisConfig.GCLZ_PREFIX + "转化成功");
            }
        }else{
            gclzs = goodsClassCustomDao.findAllbyisshow(goodsClassCustom);
        }
        return gclzs;
    }

调用了这个方法的地方有:

C:\opt\zzwelfare\welfare-front\src\main\java\com\leimingtech\front\module\tag\GoodsClassCustomTag.java
C:\opt\zzwelfare\welfare-front\src\main\java\com\leimingtech\front\module\tag\EgoodsClassCustomProductTag.java
C:\opt\zzwelfare\welfare-h5\src\main\java\com\leimingtech\extend\module\h5\category\CategoryHtml5Action.java

使用了 GoodsClassCustomTag 的地方有:

C:\opt\zzwelfare\welfare-front\src\main\webapp\WEB-INF\views_v4.0\commons\header.ftl
C:\opt\zzwelfare\welfare-front\src\main\webapp\WEB-INF\views_v4.0\search\goods-search.ftl
C:\opt\zzwelfare\welfare-front\src\main\webapp\WEB-INF\views_v4.0\category\all_class.ftl

header.ftl 中使用 GoodsClassCustomTag 的地方

        <#--<#assign goodsClassTag = newTag("goodsClassTag") />-->
        <#assign goodsClassTag = newTag("goodsClassCustomTag") />
        <#assign goodsList = goodsClassTag("") />
        <#if goodsList?exists && goodsList?size gt 0>
            <#list goodsList as class>
            <li class="classes masonry-brick">
                <div class="title">
                    <#if class.gcUrl ??&& class.gcUrl!=null>
                        <a href="${class.gcUrl}">${class.gcName}</a>
                    <#else>
                        <i></i> <a href="${base}/search/goodsSearch?searchType=gcIdSearch&keyword=${class.gcId}" title="${class.gcName}">${class.gcName}</a>
                    </#if>

                </div>
                <#if class.hasChild gt 0>
                <#assign firstchild = class.classCustomList>
                <#list firstchild as firstclass>
                    <dl>
                        <dt>
                            <#if firstclass.gcUrl ??&& firstclass.gcUrl!=null>
                                <a href="${firstclass.gcUrl}">${firstclass.gcName}</a>
                            <#else>
                                <a href="${base}/search/goodsSearch?searchType=gcIdSearch&keyword=${firstclass.gcRelId}" title="${firstclass.gcName}">${firstclass.gcName}</a>
                            </#if>
                        </dt>
                        <dd>
                            <#if firstclass.hasChild gt 0>
                            <#assign secondchild = firstclass.classCustomList>
                            <#list secondchild as secondclass>
                                <#if secondclass.gcUrl ??&& secondclass.gcUrl!=null>
                                    <a href="${secondclass.gcUrl}">${secondclass.gcName}</a>
                                <#else>
                                    <a href="${base}/search/goodsSearch?searchType=gcIdSearch&keyword=${secondclass.gcRelId}" title="${secondclass.gcName}">${secondclass.gcName}</a>
                                </#if>
                            </#list>
                            </#if>
                        </dd>
                    </dl>
                </#list>
                </#if>
            </li>
            </#list>
        </#if>

这段代码,分别使用了结果集的 classCustomList、但是并没有用到brandList。假如仅仅只去掉 brandList 的嵌套,会加快一倍的加载时间。

同时注意,classCustomList是嵌套两层用的。也就是说,如果不嵌套执行sql的话,而是使用Java来处理结果集,也只嵌套两层就可以了。

为了不影响其他使用 findAllbyisshow 的地方,新建一个方法: findAllbyisshowWithoutRecursion 处理查询结果集

C:\opt\zzwelfare\welfare-service\src\main\resources\com\leimingtech\service\module\goods\dao\mapper\GoodsClassCustomMapper.xml

    <!--非递归查询所有分类-->
    <select id="findAllbyisshowWithoutRecursion" resultMap="BaseResultMap8" parameterType="com.leimingtech.core.entity.GoodsClassCustom">
        SELECT
        s.gc_id,s.gc_parent_id,s.gc_rel_gcid,s.gc_name,s.gc_pic,s.gc_sort,s.gc_show,s.gc_title,s.gc_keywords,
        s.gc_description,s.gc_idpath,s.gc_url,s.gc_adduser,s.gc_upuser,s.gc_advid,s.create_time,s.update_time
        FROM shop_goods_class_custom s
        where
        <if test="gcshow != null and gcshow != ''">
             s.gc_show=#{gcshow}
        </if>
        order by s.gc_sort DESC
    </select>

注意这里去掉了 gc_parent_id ='0' 这个条件

用Java处理返回结果集:

C:\opt\zzwelfare\welfare-service\src\main\java\com\leimingtech\service\module\goods\service\impl\GoodsClassCustomServiceImpl.java

    /**
     * 查询所有的分类
     * @return
     */
    @Override
    public List<GoodsClassCustom> findAllbyisshowWithoutRecursion(GoodsClassCustom goodsClassCustom) {
        List<GoodsClassCustom> gclzs = new ArrayList<>();
        List<GoodsClassCustom> allCategoryList = null;
        if(JedisConfig.JEDIS_STATUS){
            ////需要安装redis
            Object obj = JedisUtils.getObject(JedisConfig.GCLZ_PREFIX + "goodsClassCustom");
            if(obj == null){
                allCategoryList = goodsClassCustomDao.findAllbyisshowWithoutRecursion(goodsClassCustom);
                //10分钟
                JedisUtils.setObject(JedisConfig.GCLZ_PREFIX + "goodsClassCustom", allCategoryList, JedisConfig.JEDIS_EXPIRE);
                log.debug(JedisConfig.GCLZ_PREFIX + "存入redis");
            }else{
                allCategoryList = (List<GoodsClassCustom>)obj;
                log.debug(JedisConfig.GCLZ_PREFIX + "转化成功");
            }
        }else{
            allCategoryList = goodsClassCustomDao.findAllbyisshowWithoutRecursion(goodsClassCustom);
        }
        if(null != allCategoryList && allCategoryList.size() > 0) {
            for(GoodsClassCustom children: allCategoryList) {

                // 顶层:ParentId == 0
                if(children.getGcParentId().equals("0")) {
                    GoodsClassCustom custom = new GoodsClassCustom();
                    custom.setGcId(children.getGcId());
                    custom.setGcParentId(children.getGcParentId());
                    custom.setGcRelId(children.getGcRelId());
                    custom.setGcName(children.getGcName());
                    custom.setGcPic(children.getGcPic());
                    custom.setGcSort(children.getGcSort());
                    custom.setGcshow(children.getGcshow());
                    custom.setGcTitle(children.getGcTitle());
                    custom.setGcDescription(children.getGcDescription());
                    custom.setGcIdpath(children.getGcIdpath());

                    custom.setGcUrl(children.getGcUrl());
                    custom.setGcAddUser(children.getGcAddUser());
                    custom.setGcUpUser(children.getGcUpUser());
                    custom.setGcAdvid(children.getGcAdvid());
                    custom.setCreateTime(children.getCreateTime());
                    custom.setUpdateTime(children.getUpdateTime());

                    if (!gclzs.contains(custom)) {
                        gclzs.add(custom);
                    }
                }
            }

            // 模板生成菜单的时候只有两层,所以,处理两层就可以了。
            for(GoodsClassCustom custom: gclzs) {
                for(GoodsClassCustom children: allCategoryList) {
                    if(custom.getGcId().equals(children.getGcParentId())) {

                        custom.setHasChild(1);
                        List<GoodsClassCustom> sons;
                        if(null == custom.getClassCustomList()) {
                            sons = new ArrayList<>();
                            custom.setClassCustomList(sons);
                        } else {
                            sons = custom.getClassCustomList();
                        }

                        sons.add(children);
                    }
                }
            }

            for(GoodsClassCustom custom: gclzs) {
                List<GoodsClassCustom> sons = custom.getClassCustomList();
                if(null != sons && sons.size() > 0 ) {
                    for(GoodsClassCustom son: sons) {

                        for(GoodsClassCustom children: allCategoryList) {
                            if(son.getGcId().equals(children.getGcParentId())) {

                                son.setHasChild(1);
                                List<GoodsClassCustom> grandsons;
                                if(null == son.getClassCustomList()) {
                                    grandsons = new ArrayList<>();
                                    son.setClassCustomList(grandsons);
                                } else {
                                    grandsons = son.getClassCustomList();
                                }

                                grandsons.add(children);

                            }
                        }
                    }
                }
            }
        }
        return gclzs;
    }

相关文章

  • B2B2B2C 电商系统首页导航优化

    定位问题 日志里出现了几千次这样的sql 这肯定是循环执行了sql了。所以,需要找循环执行的地方。 通过全局搜索 ...

  • 蚂蜂窝Java职位JD

    工作内容/职位描述: 1、负责马蜂窝电商核心业务系统架构设计及优化,进行系统改造和升级 2、优化电商交易平台架构,...

  • 电商系统架构相关问题

    电商 架构 架构按业务拆分:网站系统(登陆、首页、频道、商详、店铺),交易系统(购物车、订单、结算、支付),基础服...

  • (二)java版springcloud商城海哇VR全景电商平台-

    海哇VR全景电商平台首页功能分为几个区域,如下: 一、海哇导航区域: 左上角定位入口 搜索功能入口 消息通知入口 ...

  • 微信小程序电商实战-首页(下)

    上一篇:微信小程序电商实战-首页(上) 好了,上一期我们把首页搜索、导航栏和广告轮播给做完了,那么接下来会继续完成...

  • 2018-09-21

    产投集团APP-智慧党建系统 1、快捷导航切换优化2、更换首页图标3、更新资讯详情删除评论后不显示评论列表bug

  • 电商项目(三)

    (1)搭建前台系统。 (2)完成首页导航菜单。(学习jsonp) (3)完成CMS内容管理系统。 (4)完成首页大...

  • 电商系统服务器端性能优化(上)

    考验一个电商系统的性能不在于平时的表现如何,而在于高峰期是否能抗住压力。因此可以说电商系统服务器端系统优化的目标是...

  • 手摸手教你实现图片懒加载

    懒加载(Lazy-Load)。它是针对图片加载时机的优化:在一些图片量比较大的网站(比如电商网站首页,或者团购网站...

  • 电商交易系统-写在前面的话

    电商系统发展的比较成熟,针对自己参与已经了解过的电商系统做一个总结 1.电商交易系统-商品信息 2.电商交易系统-...

网友评论

    本文标题:B2B2B2C 电商系统首页导航优化

    本文链接:https://www.haomeiwen.com/subject/ndzxdftx.html