MyBatis使用collection标签进行多层级嵌套查询


1.首先了解一下需求

目标是写一个接口,活动码表查询接口。

先看一下表结构和表数据。

 

 

 

 

 

要执行的操作是层级结构查询,通过活动分类(activity_type)查询所有活动名称(activity_name),再通过所有活动名称(activity_name)查询所有活动一级名称(activity_level1_name)及(activity_level1_code)。

至此结束。

2.思路(先说一下我第一次的思路)

首先,查出所有的活动分类并存储在一个List<String>数组中。

然后通过循环遍历这个数组,查出所有活动名称并存储在一个List<String>数组中。

再通过遍历这个数组,查出所有活动一级名称并存储在一个List<String>数组中。

然后在每个循环内进行数据的组装。

比如:map.put("activityName", typeList.get(i));

        map.put("child", firstNameList);

等等。。。。。。最后经过我不懈的努力,终于把数据格式组装好了,开心了半天把接口提上去了,本以为前端同学能够正常使用。。。结果。。。

3.问题出现

前端同学反馈,代码响应时间过长,无法使用,需要后端进行接口的优化。

当时使用PostMan测接口的时候确实发现了这个问题,但是当时对这个问题并不敏感,下次一定要注意。

我们再次使用PostMan进行测试,查看请求时间。

 

 

 真不错,12.87秒,估计客户可以抓一把瓜子边磕边等了。。。。。。

为什么会慢?(小白,努力ing)

看一下代码。

    @Override
    public List<Map> queryListNew() {

        List<String> list = jfMarketingActivityMapper.queryActivityTypeList();

        List<Map<String, Object>> activityNameList = new ArrayList<>();

        List title = new ArrayList();

        Map<String, Object> mapType;

        Map<String, Object> mapName;

        Map<String, Object> nameCode;

        List codeList;

        for (int i = 0 ; i < list.size() ; i++) {
            List<String> typeList = jfMarketingActivityMapper.typeList(list.get(i));
            for (int j = 0 ; j < typeList.size() ; j++) {
                List<String> firstNameList = jfMarketingActivityMapper.firstNameList(typeList.get(j));
                mapName = new HashMap<>();
                mapName.put("activityName", typeList.get(j));
                codeList = new ArrayList();
                for (int k = 0 ; k < firstNameList.size() ; k++) {
                    String code = jfMarketingActivityMapper.firstName(firstNameList.get(k));
                    nameCode = new HashMap<>();
                    nameCode.put("activityLevel1Code", code);
                    nameCode.put("activityName", code + "_" + firstNameList.get(k));
                    codeList.add(k, nameCode);
                }
                mapName.put("child", codeList);
                activityNameList.add(j, mapName);
            }
            mapType = new HashMap<>();
            mapType.put("activityName", list.get(i));
            mapType.put("child", activityNameList);

            activityNameList = new ArrayList<>();

            title.add(i, mapType);

        }

        return title;
    }

可以看到,在三层循环中,我们不断的调用Mapper层进行sql的查询操作。每次查询都需要时间,三层循环之下导致时间过长。

所以我们要尽量减少sql的查询操作。

4.collection标签

之前做过的一个模块中,使用到了MyBatis的collection标签。当时是需要给前端返回一个树级的结构,一个层级关系。

于是我就想到应该可以直接在sql中把层级结构搂出来,这样就大大减少了接口的响应时间。

不太一样的地方就是这个层级是三级,可能需要嵌套使用collection标签。

ServiceImpl层:

List<String> typeList = jfMarketingActivityMapper.queryActivityTypeList();

List<Map> allData = jfMarketingActivityMapper.allList(typeList);

for (int i = 0 ; i < allData.size() ; i++) {
List list = (List) allData.get(i).get("child");
for (int j = 0 ; j < list.size() ; j++) {
Map<String, Object> map = (Map<String, Object>) list.get(j);
List list1 = (List) map.get("child");
for (int k = 0 ; k < list1.size() ; k++) {
Map<String, Object> map1 = (Map<String, Object>) list1.get(k);
map1.put("activityName", map1.get("activityLevel1Code") + "_" + map1.get("activityName"));
}
}
}

return allData;

}
 

Mapper层:

List<Map> allList(@Param("typeList") List<String> typeList);

MyBatis层:

    <resultMap id="child" type="java.util.Map">
        <result property="activityName" column="activity_name"/>
        <collection property="child" ofType="java.util.Map" javaType="ArrayList" resultMap="child2">
        </collection>
    </resultMap>

    <resultMap id="child2" type="java.util.Map">
        <result property="activityName" column="activity_level1_name"/>
        <result property="activityLevel1Code" column="activity_level1_code"/>
    </resultMap>

    <resultMap id="list" type="java.util.Map">
        <result property="activityName" column="activity_type"/>
        <collection property="child" ofType="java.util.Map" javaType="ArrayList" resultMap="child">
        </collection>
    </resultMap>

    <select id="allList" resultMap="list">
        SELECT activity_type, activity_name, activity_level1_name, activity_level1_code
        FROM jf_marketing_activity
        WHERE 1=1 AND activity_type IN
        <foreach collection="typeList" item="list" index="index" open="(" separator="," close=")">
            #{list}
        </foreach>

    </select>

代码实现,通过MyBatis层使用collection标签进行多层级嵌套查询,实现类中的循环是前端要求拼接code所以进行循环。

 

 可以看到接口响应时间变成96ms,12.87s和96ms,一百三十多倍。。。。。。

5.总结

下次写代码的时候不光要只考虑能实现,还要考虑一些性能方面的问题。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM