慎用while!!!

项目的一个查询接口在实际使用时既没报错,也没返回查询结果,再多次查询后发现系统cpu飙升,并且mongo的cpu也占用很高,怀疑在查询过程中写了死循环(当然,不是我写的)
于是查看接口代码,如下

//一张试卷的基本元数据  companyName examineeName userid openid ;oneLevelDirectory; twoLevelDirectory;
        JSONObject papger = new JSONObject();
        papger.put("paperMetadata", paperMetadata);
        String twoLevelDirectory = paperMetadata.getString("twoLevelDirectory");
        String oneLevelDirectory = paperMetadata.getString("oneLevelDirectory");
        String platName=paperMetadata.getString("platName");
        Query queryAll = new Query();
        queryAll.addCriteria(Criteria.where("oneLevelDirectory").is(oneLevelDirectory));
        //非综合考试
        if (StringUtils.isNoneEmpty(twoLevelDirectory)&&!"综合问答".equals(twoLevelDirectory)) {
            queryAll.addCriteria(Criteria.where("twoLevelDirectory").is(twoLevelDirectory));
        }
        long allQuestions = mongoTemplate.count(queryAll, "exam_question");
        if(allQuestions<PAPER_SIZE){
            return ResultJSON.FALSE("题库数量不足:" + allQuestions);
        }
        List<JSONObject> allQuestionInfos = new ArrayList<>();
        long startTime  = System.currentTimeMillis();
        while (allQuestionInfos.size() < PAPER_SIZE) {
            int skipStep = RandomUtil.randomInt((int) (allQuestions));
            queryAll = new Query();
            queryAll.addCriteria(Criteria.where("oneLevelDirectory").is(oneLevelDirectory));
            //非综合考试
            if (StringUtils.isNoneEmpty(twoLevelDirectory)&&!"综合问答".equals(twoLevelDirectory)) {
                queryAll.addCriteria(Criteria.where("twoLevelDirectory").is(twoLevelDirectory));
            }
            if(StringUtils.isNotEmpty(platName)){
                queryAll.addCriteria(Criteria.where("platName").is(platName));
            }
            queryAll.limit(1);
            queryAll.skip(skipStep);
            List<JSONObject> allSearchResultQuestionInf = mongoTemplate.find(queryAll,JSONObject.class,"exam_question");
            if(allSearchResultQuestionInf.size()==0){
                continue;
            }
            JSONObject question = allSearchResultQuestionInf.get(0);
            boolean isLive = false;
            for (JSONObject allQuestionInfo : allQuestionInfos) {
                if (allQuestionInfo.getLongValue("qid") == question.getLongValue("qid")) {
                    isLive = true;
                    break;
                }
            }
            if(allQuestionInfos.size()<PAPER_SIZE&&!isLive){
                allQuestionInfos.add(question);
            }
        }
        papger.put("paperQuestionList", allQuestionInfos);
        JSONObject performance =  new JSONObject();
        performance.put("paperCreateTime", System.currentTimeMillis());
        performance.put("paperCreateTimeFmt", SIMPLE_DATE_FORMAT.format(new Date()));
        performance.put("papaerCreateTimeConsuming", (System.currentTimeMillis()-startTime));
        papger.put("performance",performance);
        return ResultJSON.SUCCESS("试卷生成成功",papger);

问题出在这个 allQuestionInfos.add这里,如果没有满足条件,则不会加到集合里面去,那么集合长度会永远小于 PAPER_SIZE(20),则会导致死循环,并且还会一直查询数据库,调用四五次这个方法,那整个系统直接GG了。
发现问题之后将while改成了for循环,并优化了查询的代码,如下:

//一张试卷的基本元数据  companyName examineeName userid openid ;oneLevelDirectory; twoLevelDirectory;
        JSONObject papger = new JSONObject();
        papger.put("paperMetadata", paperMetadata);
        String twoLevelDirectory = paperMetadata.getString("twoLevelDirectory");
        String oneLevelDirectory = paperMetadata.getString("oneLevelDirectory");
        String platName=paperMetadata.getString("platName");
        Query queryAll = new Query(Criteria.where("oneLevelDirectory").is(oneLevelDirectory));
        if(StringUtils.isNotEmpty(platName)){
            queryAll.addCriteria(Criteria.where("platName").is(platName));
        }
        //非综合考试
        if (StringUtils.isNoneEmpty(twoLevelDirectory)&&!"综合问答".equals(twoLevelDirectory)) {
            queryAll.addCriteria(Criteria.where("twoLevelDirectory").is(twoLevelDirectory));
        }
        long allQuestions = mongoTemplate.count(queryAll, "exam_question");
        if(allQuestions<PAPER_SIZE){
            return ResultJSON.FALSE("题库数量不足:" + allQuestions);
        }
        List<JSONObject> allQuestionInfos = new ArrayList<>();
        Set<Long> set = new HashSet<>();
        long startTime  = System.currentTimeMillis();
        for (int i = 0; i < PAPER_SIZE*50; i++) {
            int skipStep = RandomUtil.randomInt((int) (allQuestions));
            queryAll.limit(1);
            queryAll.skip(skipStep);
            JSONObject one = mongoTemplate.findOne(queryAll,JSONObject.class,"exam_question");
            if(one==null){
                continue;
            }
            if(!set.contains(one.getLongValue("qid"))){
                allQuestionInfos.add(one);
                set.add(one.getLongValue("qid"));
                if(allQuestionInfos.size()==PAPER_SIZE){
                    break;
                }
            }
        }
        papger.put("paperQuestionList", allQuestionInfos);
        JSONObject performance =  new JSONObject();
        performance.put("paperCreateTime", System.currentTimeMillis());
        performance.put("paperCreateTimeFmt", SIMPLE_DATE_FORMAT.format(new Date()));
        performance.put("papaerCreateTimeConsuming", (System.currentTimeMillis()-startTime));
        papger.put("performance",performance);
        return ResultJSON.SUCCESS("试卷生成成功",papger);

辣鸡代码,勿喷。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值