zoukankan      html  css  js  c++  java
  • 结对编程项目

    结对编程

    要求

    软工作业 结对编程:实现一个自动生成小学四则运算题目的命令行程序
    作业要求 结对项目要求
    作业目标 一个自动生成小学四则运算题目的命令行程序,附带判断对错和题目查重功能

    合作者

    李纪然3218005441

    陈雪莹3218005439

    GitHub地址

    李纪然https://github.com/CIELIEL/3218005441
    陈雪莹https://github.com/deerc123/jiedui

    PSP表格

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 30 30
    ·Estimate ·估计这个任务需要多少时间 1440 1680
    Development 开发 60 30
    ·Analysis ·需求分析(包括学习新技术) 300 360
    ·Design Spec ·生成设计文档 60 90
    ·Design Review ·设计复审(和同事审核设计文档) 30 30
    ·Coding Standard ·代码规范(为目前的开发制定合适的规范) 30 30
    ·Design ·具体设计 60 50
    ·Coding ·具体编码 600 670
    ·Code Review ·代码复审 180 300
    · Test ·测试(自我测试,修改代码,提交修改) 180 240
    Reporting 报告 120 150
    ·Test Report ·测试报告 30 20
    ·Size Measurement ·计算工作量 10 10
    ·Postmortem&Process Improvement Plan ·事后总结,并提出过程改进计划 10 10
    合计 1700 2020

    效能分析

    改进思路

    改进程序耗费时间:大约8个小时

    四则运算:在getresult()方法中:当碰到符号为减法时,我们通过判断左右结点的大小来决定是否调换左右结点的位置,这样就能避免生成负数的情况,当碰到符号为除法时,判断除数是否为0,为0则重新随机符号(除了/)

    查重:利用DuplicateCheck类中的CompareStringByChar(String strA,String strB)方法判断两个String如果满足条件两个字符串所含元素相同、所含每个元素数量相等、字符串长度相等,就返回ture。这样可以比直接比较字符串更准确判断出题目是否相等

    性能分析图

    CPU占比

    时间占比


    空间占比

    由图可得,程序中消耗最大的函数为BinaryTree类中的createBTree方法

    设计实现过程

    代码的类

    代码关系

    (Test类)主函数:输入题目数量参数和选择操作代表值—(调用)—>(CreatSubjects类)输入生成运算符数量参数,输出运行后的结果,判断答题对错

    (CreatSubjects类)—(调用)—>(BinaryTree类)createBTree() 方法:生成二叉树;CalAndVal()方法:得出运行后的结果并打印到Answer文档;toString()方法:打印中序遍历二叉树的结果到Exan文档

    (BinaryTree类)—(调用)—(1)(Ran类)getOperator()方法:随机生成有孩子结点的符号;getnumber()方法:获取叶子结点的数值;getChildPlace()方法:根据运算符的个数随机产生子节点的位置(2)(TreeNode类)getresult()方法:获取四则运算后的结果;toString()方法:根据去括号法则去掉多余的括号并获取去括号后的运算式

    (TreeNode类)—(调用)—(1)(FractionStack类)setNumerator()方法:设置分子;setDenominator()方法:设置分母;getRealRes()方法:将分数运算后的结果转化成真分数形式(2)(FractionCal类)fracAdd()方法:进行分数加法运算;fracSub()方法:进行分数减法运算;fracMul()方法:进行分数乘法运算;fractDiv()方法:进行分数除法运算

    (FractionCal类)—(调用)—(FractionStack类):分装一个分数供运算

    (BinaryList类):存储二叉树以供查重

    (DuplicateCheck类):查重算法

    代码说明

    核心代码展示

    生成二叉树

     public void createBTree() {
            TreeNode lchild, rchild, lnode, rnode;
            String check;
           do {
               if (num == 1) {
                   lchild = new TreeNode(String.valueOf(Ran.getNumber(100)), null, null);
                   rchild = new TreeNode(String.valueOf(Ran.getNumber(100)), null, null);
                   root = new TreeNode(String.valueOf(Ran.getOperator()), lchild, rchild);
               } else {
                   int num1 = 0;
                   int n = getDeep() - 3;
                   boolean[] place = Ran.getChildPlace(num);
                   char rootString = Ran.getOperator();
                   root = new TreeNode(String.valueOf(rootString), null, null);
                   opeList.add(root);
    
    
                   //System.out.println(root.getStr());
    
                   for (int i = 0; i < n; i++) {
                       for (int j = 0; j < (int) Math.pow(2, i); j++, num1++) {
                           lchild = new TreeNode(String.valueOf(Ran.getOperator()), null, null);
                           rchild = new TreeNode(String.valueOf(Ran.getOperator()), null, null);
                           opeList.get(j + num1).setChild(lchild, rchild);
                           opeList.add(lchild);
                           opeList.add(rchild);
                       }
                   }
    
                   for (int i = 0; i < place.length; i++) {
                       if (place[i]) {
                           int a1 = Ran.getNumber(10);
                           lnode = new TreeNode(String.valueOf(Ran.getNumber(100)), null, null);
                           rnode = new TreeNode(String.valueOf(Ran.getNumber(100)), null, null);
                           if (i % 2 == 0) {
                               lchild = new TreeNode(String.valueOf(Ran.getOperator()), lnode, rnode);
                               opeList.add(lchild);
                               opeList.get(num1).setLchild(lchild);
                           } else {
                               rchild = new TreeNode(String.valueOf(Ran.getOperator()), lnode, rnode);
                               opeList.add(rchild);
                               opeList.get(num1).setRchild(rchild);
                           }
                       } else {
                           if (i % 2 == 0) {
                               lchild = new TreeNode(String.valueOf(Ran.getNumber(100)), null, null);
                               opeList.get(num1).setLchild(lchild);
                           } else {
    
                               rchild = new TreeNode(String.valueOf(Ran.getNumber(100)), null, null);
                               opeList.get(num1).setRchild(rchild);
                           }
                       }
                       num1 = num1 + i % 2;
                   }
                   //BinaryList binaryList=new BinaryList();
                  // String check=deleteCharString0(root.toString(),')','(');
                   //binaryList.saveBinary(deleteCharString0(root.toString(),')','('));
    
                   //BinaryList args=new BinaryList();
                   //args.args(root);
                   //RootSave rootSave=new RootSave();
                   //rootSave.saveRoot(rootString);
                   //binaryTreesList.add(this);
               }
               //check=deleteCharString0(root.toString(),')','(');
           }while (DuplicateCheck.checkDuplicate(root.toString(),BinaryList.saveList)||root.getLchild()==null||root.getRchild()==null);
            BinaryList.saveBinary(deleteCharString0(root.toString(),')','('));
    

    四则运算

      public String getResult(ArrayList arrayList) {
            if (hasChild()) {
                switch (str) {
                    case "+":
                        //左右子树如果有孩子,说明左右子树是一个表达式,而不是数字节点。
                        if (getRchild().hasChild() || getLchild().hasChild()) {
    
    
                            //判断左右邻括号的运算符是否为'/',是的话进入分数运算
                            if (getRchild().str.equals("/") || getLchild().str.equals("/")) {
    
                                if (getRchild().str.equals("/") && getLchild().str.equals("/")) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getLchild().getResult(arrayList)));
                                    f1.setDenominator(Integer.parseInt(getLchild().getRchild().getResult(arrayList)));
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getLchild().getResult(arrayList)));
                                    f2.setDenominator(Integer.parseInt(getRchild().getRchild().getResult(arrayList)));
                                    FractionCal f = new FractionCal();
                                    return f.fracAdd(f1, f2).getRealRes();
                                }
    
    
                                if ((getLchild().str.equals("+") || getLchild().str.equals("-") || getLchild().str.equals("*") || !(getLchild().hasChild())) && getRchild().str.equals("/")) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getResult(arrayList)));
                                    f1.setDenominator(1);
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getLchild().getResult(arrayList)));
                                    f2.setDenominator(Integer.parseInt(getRchild().getRchild().getResult(arrayList)));
                                    FractionCal f = new FractionCal();
    
                                    return f.fracAdd(f1, f2).getRealRes();
                                }
    
                                if (getLchild().str.equals("/") && (getRchild().str.equals("+") || getRchild().str.equals("-") || getRchild().str.equals("*") || !(getRchild().hasChild()))) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getLchild().getResult(arrayList)));
                                    f1.setDenominator(Integer.parseInt(getLchild().getRchild().getResult(arrayList)));
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getResult(arrayList)));
                                    f2.setDenominator(1);
                                    FractionCal f = new FractionCal();
                                    return f.fracAdd(f1, f2).getRealRes();
                                }
    
                            }
                             return String.valueOf(Integer.parseInt(getLchild().getResult(arrayList)) + Integer.parseInt(getRchild().getResult(arrayList)));
                        }
                        return String.valueOf(Integer.parseInt(getLchild().getResult(arrayList)) + Integer.parseInt(getRchild().getResult(arrayList)));
    
    
                    case "-":
    
                        //左右子树如果有孩子,说明左右子树是一个表达式,而不是数字节点。
                        if (getRchild().hasChild() || getLchild().hasChild()) {
    
    
                            //判断左右邻括号的运算符是否为'/'
                            if (getRchild().str.equals("/") || getLchild().str.equals("/")) {
    
    
                                if (getRchild().str.equals("/") && getLchild().str.equals("/")) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getLchild().getResult(arrayList)));
                                    f1.setDenominator(Integer.parseInt(getLchild().getRchild().getResult(arrayList)));
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getLchild().getResult(arrayList)));
                                    f2.setDenominator(Integer.parseInt(getRchild().getRchild().getResult(arrayList)));
                                    FractionCal f = new FractionCal();
                                    if ((f.fracSub(f1, f2).getRealRes()).charAt(0) == '-') {
                                        TreeNode treeNode = new TreeNode();
                                        treeNode = getLchild();
                                        this.lchild = this.rchild;
                                        this.rchild = treeNode;
    
    
                                        FractionCal f5 = new FractionCal();
                                        return f5.fracSub(f2, f1).getRealRes();
                                    }
                                    return f.fracSub(f1, f2).getRealRes();
                                }
    
    
                                if (getLchild().str.equals("+") || getLchild().str.equals("-") || getLchild().str.equals("*") || !(getLchild().hasChild())) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getResult(arrayList)));
                                    f1.setDenominator(1);
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getLchild().getResult(arrayList)));
                                    f2.setDenominator(Integer.parseInt(getRchild().getRchild().getResult(arrayList)));
                                    FractionCal f = new FractionCal();
                                    if ((f.fracSub(f1, f2).getRealRes()).charAt(0) == '-') {
                                        TreeNode treeNode = new TreeNode();
                                        treeNode = getLchild();
                                        this.lchild = this.rchild;
                                        this.rchild = treeNode;
    
                                        FractionCal f5 = new FractionCal();
                                        return f5.fracSub(f2, f1).getRealRes();
                                    }
                                    return f.fracSub(f1, f2).getRealRes();
                                }
    
    
                                if (getLchild().str.equals("/") && (getRchild().str.equals("+") || getRchild().str.equals("-") || getRchild().str.equals("*") || !(getRchild().hasChild()))) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getLchild().getResult(arrayList)));
                                    f1.setDenominator(Integer.parseInt(getLchild().getRchild().getResult(arrayList)));
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getResult(arrayList)));
                                    f2.setDenominator(1);
                                    FractionCal f = new FractionCal();
                                    if ((f.fracSub(f1, f2).getRealRes()).charAt(0) == '-') {
                                        TreeNode treeNode = new TreeNode();
                                        treeNode = getLchild();
                                        this.lchild = this.rchild;
                                        this.rchild = treeNode;
    
                                        FractionCal f5 = new FractionCal();
                                        return f5.fracSub(f2, f1).getRealRes();
                                    }
    
                                    return f.fracSub(f1, f2).getRealRes();
    
                                }
    
                            }
                            if (Integer.parseInt(getLchild().getResult(arrayList)) > Integer.parseInt(getRchild().getResult(arrayList)) || Integer.parseInt(getLchild().getResult(arrayList)) == Integer.parseInt(getRchild().getResult(arrayList))) {
                                return String.valueOf(Integer.parseInt(getLchild().getResult(arrayList)) - Integer.parseInt(getRchild().getResult(arrayList)));
                            }
                            if (Integer.parseInt(getLchild().getResult(arrayList)) < Integer.parseInt(getRchild().getResult(arrayList))) {
                                TreeNode treeNode = new TreeNode();
                                treeNode = getLchild();
                                this.lchild = this.rchild;
                                this.rchild = treeNode;
                                return  String.valueOf(Integer.parseInt(getLchild().getResult(arrayList)) - Integer.parseInt(getRchild().getResult(arrayList)));
                            }
                            return this.getResult(arrayList);
                        }
                        
                
    
    
    
                        else {
                            if (Integer.parseInt(getLchild().str) > Integer.parseInt(getRchild().str) || Integer.parseInt(getLchild().str) == Integer.parseInt(getRchild().str)) {
                                return String.valueOf(Integer.parseInt(getLchild().str) - Integer.parseInt(getRchild().str));
                            }
                            if (Integer.parseInt(getLchild().getResult(arrayList)) < Integer.parseInt(getRchild().getResult(arrayList))) {
                                TreeNode treeNode = new TreeNode();
                                treeNode = getLchild();
                                this.lchild = this.rchild;
                                this.rchild = treeNode;
                                return String.valueOf(Integer.parseInt(getLchild().str) - Integer.parseInt(getRchild().str));
                            }
                          //  return this.getResult(arrayList);
    
                        }
    
    
    
    
                    case "*":
    
                        //左右子树如果有孩子,说明左右子树是一个表达式,而不是数字节点。
                        if (getRchild().hasChild() || getLchild().hasChild()) {
                            //判断左右邻括号的运算符是否为'/'
                            if (getRchild().str.equals("/") || getLchild().str.equals("/")) {
                                if (getRchild().str.equals("/") && getLchild().str.equals("/")) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getLchild().getResult(arrayList)));
                                    f1.setDenominator(Integer.parseInt(getLchild().getRchild().getResult(arrayList)));
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getLchild().getResult(arrayList)));
                                    f2.setDenominator(Integer.parseInt(getRchild().getRchild().getResult(arrayList)));
                                    FractionCal f = new FractionCal();
                                    return f.fracMul(f1, f2).getRealRes();
                                } else if (getLchild().str.equals("+") || getLchild().str.equals("-") || getLchild().str.equals("*") || !(getLchild().hasChild())) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getResult(arrayList)));
                                    f1.setDenominator(1);
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getLchild().getResult(arrayList)));
                                    f2.setDenominator(Integer.parseInt(getRchild().getRchild().getResult(arrayList)));
                                    FractionCal f = new FractionCal();
    
                                    return f.fracMul(f1, f2).getRealRes();
                                }
                                FractionStack f1 = new FractionStack();
                                f1.setNumerator(Integer.parseInt(getLchild().getLchild().getResult(arrayList)));
                                f1.setDenominator(Integer.parseInt(getLchild().getRchild().getResult(arrayList)));
                                FractionStack f2 = new FractionStack();
                                f2.setNumerator(Integer.parseInt(getRchild().getResult(arrayList)));
                                f2.setDenominator(1);
                                FractionCal f = new FractionCal();
    
                                return f.fracMul(f1, f2).getRealRes();
                            }
                            return String.valueOf(Integer.parseInt(getLchild().getResult(arrayList)) * Integer.parseInt(getRchild().getResult(arrayList)));
                        }
    
                        return String.valueOf(Integer.parseInt(getLchild().getResult(arrayList)) * Integer.parseInt(getRchild().getResult(arrayList)));
    
                        /**
                         * 获取每个节点的运算结果,并检验除法
                         * 1)除数为0
                         * 2)不能整除
                         * 出现以上两种情况的话将该运算符转换成其他三种运算符
                         *
                         * @return result
                         */
                    case "/":
                        if (getRchild().getResult(arrayList).equals("0")||getRchild().getResult(arrayList).equals("0")) {
                            while (str.equals("/")) {
                                str = String.valueOf(Ran.getOperator());
                                System.out.println(str);
                            }
                            return this.getResult(arrayList);
                        }
    
                        //左右子树如果有孩子,说明左右子树是一个表达式,而不是数字节点。
                        if (getRchild().hasChild() || getLchild().hasChild()) {
                            //判断左右邻括号的运算符是否为'/'
                            if (getRchild().str.equals("/") || getLchild().str.equals("/")) {
    
                                if (getRchild().str.equals("/") && getLchild().str.equals("/")) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getLchild().getResult(arrayList)));
                                    f1.setDenominator(Integer.parseInt(getLchild().getRchild().getResult(arrayList)));
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getLchild().getResult(arrayList)));
                                    f2.setDenominator(Integer.parseInt(getRchild().getRchild().getResult(arrayList)));
                                    FractionCal f = new FractionCal();
                                    return f.fractDiv(f1, f2).getRealRes();
                                } else if (getLchild().str.equals("+") || getLchild().str.equals("-") || getLchild().str.equals("*") || !(getLchild().hasChild())) {
                                    FractionStack f1 = new FractionStack();
                                    f1.setNumerator(Integer.parseInt(getLchild().getResult(arrayList)));
                                    f1.setDenominator(1);
                                    FractionStack f2 = new FractionStack();
                                    f2.setNumerator(Integer.parseInt(getRchild().getLchild().getResult(arrayList)));
                                    f2.setDenominator(Integer.parseInt(getRchild().getRchild().getResult(arrayList)));
                                    FractionCal f = new FractionCal();
                                   
                                    return f.fractDiv(f1, f2).getRealRes();
                                }
                                FractionStack f1 = new FractionStack();
                                f1.setNumerator(Integer.parseInt(getLchild().getLchild().getResult(arrayList)));
                                f1.setDenominator(Integer.parseInt(getLchild().getRchild().getResult(arrayList)));
                                FractionStack f2 = new FractionStack();
                                f2.setNumerator(Integer.parseInt(getRchild().getResult(arrayList)));
                                f2.setDenominator(1);
                                FractionCal f = new FractionCal();
    
                                return f.fractDiv(f1, f2).getRealRes();
                            }
                        else if (Integer.parseInt(getLchild().getResult(arrayList)) % Integer.parseInt(getRchild().getResult(arrayList)) != 0) {
                            if (arrayList.indexOf(this) == 0) {
                                FractionStack f1 = new FractionStack();
                                f1.setNumerator(Integer.parseInt(getLchild().getResult(arrayList)));
                                f1.setDenominator(Integer.parseInt(getRchild().getResult(arrayList)));
    
                                return f1.getRealRes();
                            }
                        }
                            return String.valueOf(Integer.parseInt(getLchild().getResult(arrayList)) / Integer.parseInt(getRchild().getResult(arrayList)));
                            }
                           /* while (str.equals("/")) {
                                str = String.valueOf(Ran.getOperator());
                            }*/
    
                        //return this.getResult(arrayList);
    
                        return String.valueOf(Integer.parseInt(getLchild().getResult(arrayList)) / Integer.parseInt(getRchild().getResult(arrayList)));
                }
            }
            return str;
        }
    

    查重算法

    public class DuplicateCheck {
      private ArrayList<TreeNode> sameRootList = new ArrayList<>();
    
     // public boolean duplicateCheck(Character root, BinaryTree binaryTree) {
    
    
    
         // return true;
    //  }
    
      public static boolean CompareStringByChar(String strA,String strB)
      {
          boolean IsEqual = true;
          char[] arrA = strA.toCharArray();
          char[] arrB = strB.toCharArray();
          for (int i=0;i<arrA.length;i++)
          {
              char c=arrA[i];
              if (strB.indexOf(c)==-1)
              {
                  IsEqual = false;
              }
              else
              {
                  if(GetSameCharCount(c,arrA)!=GetSameCharCount(c,arrB))
                  {
                      IsEqual = false;
                  }
              }
          }
          for(int k=0;k<arrB.length;k++)//char charb in arrB
          {
              char b=arrB[k];
              if (strA.indexOf(b)==-1)//!strA.Contains(charb)
              {
                  IsEqual = false;
              }
              else
              {
                  if (GetSameCharCount(b, arrA) != GetSameCharCount(b, arrB))
                  {
                      IsEqual = false;
                  }
              }
          }
          return IsEqual;
      }
    
    //获得某字符在字符串中的数量
      private static int GetSameCharCount(Character chara,char[] arrChar)
      {
          int count = 0;
          for(int j=0;j<arrChar.length;j++)
          {
              if(chara.equals(arrChar[j]))
              {
                  count++;
              }
          }
          return count;
      }
    
    
      public static boolean checkDuplicate(String strA,ArrayList arrayList){
          int co=0;
          for(int q=0;q<arrayList.size();q++){
             if (CompareStringByChar(strA,(String) arrayList.get(0))){
                 co++;
             }
          }
          return co!=0;
      }
    
    }
    

    思路

    对于这样一棵二叉树,每个叶子节点都是数字,每个父节点都是符号,然后中序遍历结果就是我们所需要的四则运算,而且每次父节点返回的时候,可以根据符号进行运算式的计算,中序遍历的结果:

    *1+2-3*4*

    但是如何产生括号呢?

    有一个简单的办法就是父节点每次返回的时候带上括号,于是运算式就变成了这样:

    *((1+2)-(3*4))*

    正确的优先级应该是这样的:*'('、')'>'*'、'/'>'+'、'-'*

    通过整理,我们可以得到这样的规律:

    假设待去括号的表达式为 (m1 op1 n1) op (m2 op2 n2) 这里m1、n1、m2、m2可能自身就是个表达式,也可能是数字,op、op1、op2为运算符

    *1、若op为'/',则 (m2 op2 n2)的括号必须保留;*

    *2、若op为'*'或'-',如果op2为'+'或'-',则(m2 op2 n2)的括号必须保留;*

    *3、若op为'*'或'/',如果op1为'+'或'-',则(m1 op1 n1)的括号必须保留;*

    *4、 除此之外,去掉括号不影响表达式的计算顺序。*

    至此,我们就能得到一个比较随机的四则运算式。

    测试运行

    代码测试

    生成10到题目(输入操作参数1)

    生成Exam文档

    生成Answer文档

    在Exam里答题后(输入操作参数2)

    答题

    批改后

    单元测试

    分别对creatSubjects类、TreeNode类、DuplicateCheckTest类进行了单元测试,运行成功截图以及代码覆盖率截图如下

    creatSubjects类
    我们分别测试了生成10000道题目、100道题目,测试均成功。


    TreeNode类


    DuplicateCheckTest类


    项目小结

    李纪然项目小结

    我发现写代码要理清思路,逻辑清晰,才能更好的用代码实现自己的思路

    陈雪莹项目小结

    这次结对项目让我深有感触,两个人的合作果然是比一个人单干要效率高!

  • 相关阅读:
    中国式沟通
    10 表连接优化
    09 优化数据访问
    07 SQL优化技术
    06 执行计划
    04 系统和对象统计信息
    03 找出性能问题
    02 key concept
    Xpert 调优
    JavaWeb_常用功能_01_文件上传
  • 原文地址:https://www.cnblogs.com/deerc123/p/13800589.html
Copyright © 2011-2022 走看看