You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Java代码缩短执行时间?原PHP版本执行效率更高

Java ResultSet处理与数据库写入代码优化方案

这段代码用于处理ResultSet并向数据库写入异常数据,当前相比PHP实现耗时翻倍,以下是针对性的优化方案:

原代码

private String queryExtractor(JdbcTemplate template, Integer idExecution, String replaceSql, RequeteLite req ){
    return (String) template.query(replaceSql, new ResultSetExtractor<Integer>() {           
        int idRequete = req.getIdRequete();

        @Override
        public Integer extractData(ResultSet rs) throws SQLException, DataAccessException {
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();
            //遍历行数
            while(rs.next()){
                String cleAno="";
                cleAno= String.format("%sid_requete=%s", cleAno,req.getIdRequete());
                Map<String,String> hmap = new HashMap<>();
                //遍历列数
                for (int j = 1; j <= columnCount ; j++) {
                    String colName = rsmd.getColumnName(j);
                    Integer coltype = rsmd.getColumnType(j);
                    boolean test = coltype.equals(java.sql.Types.DOUBLE);
                    if(test){
                        Double colValeur = rs.getDouble(j);
                        String valeur = colValeur.toString();
                        if("".equals(valeur) || valeur == null){
                            valeur = "NULL";
                        }
                        hmap.put(colName, valeur);
                    }else{
                        String colValeur = rs.getString(j);
                        if("".equals(colValeur) || colValeur == null){
                            colValeur = "NULL";
                        }
                        hmap.put(colName, colValeur);
                    }
                                      
                }
                Map<String,String> sortedMap = new TreeMap<>(hmap);

                for(Map.Entry<String, String> entry : sortedMap.entrySet()) {
                    cleAno = String.format("%s&%s=%s", cleAno,entry.getKey(),entry.getValue()); 
                }

                //检查异常是否已存在                                  
                if(!ligneAnomalieDAO.existAnomalie(cleAno)){ 
                    //异常不存在
                    //插入异常
                    LigneAnomalie ligneAno = new LigneAnomalie(idRequete, cleAno);
                    Integer idLigneAnomalie = ligneAnomalieManager.addLigne(ligneAno);

                    //插入字段到champLigneAnomalie表             
                    for(Map.Entry<String, String> entry : sortedMap.entrySet()) {
                        ChampLigneAnomalie champLigneAno = new ChampLigneAnomalie(idLigneAnomalie, entry.getKey(), entry.getValue());
                        champligneAnoManager.addChamp(champLigneAno);             
                    }                                       
                }else{
                    //异常已存在
                    //检查异常是否有备注
                    Integer idLigneAno = ligneAnomalieDAO.findLigneByCle(cleAno).getIdLigneAnomalie();
                    if(justificationDAO.existJustification(idLigneAno)){
                        //异常有备注
                        JustificationAnomalie justificationAno  = justificationDAO.findJustifByIdLigneAnomalie(idLigneAno);
                        if(justificationAno.getType().equals("correction")){
                            //备注是修正类型,取消修正(因为如果已修正就不该再出现异常)
                            justificationAno.setCommentaire("异常未被修正(查询 "+ req.getTitre() +" 再次遇到该异常)");
                            justificationAno.setValidJustification(0);
                            justificationDAO.updateJustif(justificationAno);
                        }  
                    }
                }
                Integer idLigneAno = ligneAnomalieDAO.findLigneByCle(cleAno).getIdLigneAnomalie();
                LLigneAnomalieExecutionJeu lligneAnoExe = new LLigneAnomalieExecutionJeu(idExecution, idLigneAno);
                lligneAnoExeManager.addLLAE(lligneAnoExe);
            }
            return null;
        }           
    });        
} 

核心优化方案

1. 减少数据库交互(性能瓶颈核心)

数据库IO是最大耗时点,当前代码每行多次查询/写入,必须批量处理+缓存:

  • 缓存重复查询结果:用HashMap<String, Integer>缓存cleAno对应的idLigneAnomalie,避免重复调用findLigneByCle:
    // 在extractData开头初始化缓存
    Map<String, Integer> cleToIdCache = new HashMap<>();
    
    // 后续获取id时优先查缓存
    Integer idLigneAno = cleToIdCache.get(cleAno);
    if (idLigneAno == null) {
        idLigneAno = ligneAnomalieDAO.findLigneByCle(cleAno).getIdLigneAnomalie();
        cleToIdCache.put(cleAno, idLigneAno);
    }
    
  • 批量执行写入操作:把addLigne、addChamp、addLLAE改成批量接口,收集一批数据后一次性插入,避免单条SQL反复执行:
    // 初始化批量集合
    List<LigneAnomalie> ligneAnoBatch = new ArrayList<>();
    List<ChampLigneAnomalie> champBatch = new ArrayList<>();
    List<LLigneAnomalieExecutionJeu> llaeBatch = new ArrayList<>();
    
    // 循环内只添加到集合,不立即写入
    ligneAnoBatch.add(ligneAno);
    // ... 其他对象同理
    
    // 每1000条提交一次,或循环结束后统一提交
    if (ligneAnoBatch.size() >= 1000) {
        ligneAnomalieManager.batchAddLigne(ligneAnoBatch);
        ligneAnoBatch.clear();
    }
    
  • 合并查询操作:将existJustification和findJustifByIdLigneAnomalie合并为一个方法,一次查询获取是否存在及实体,减少DB调用次数。

2. 减少对象创建与优化字符串操作

循环内频繁创建对象会触发频繁GC,字符串拼接效率极低:

  • 用StringBuilder替代String.format拼接:cleAno的拼接改用StringBuilder,提前预估容量减少扩容:
    StringBuilder cleAnoSb = new StringBuilder(256);
    cleAnoSb.append("id_requete=").append(req.getIdRequete());
    for(Map.Entry<String, String> entry : sortedMap.entrySet()) {
        cleAnoSb.append('&').append(entry.getKey()).append('=').append(entry.getValue());
    }
    String cleAno = cleAnoSb.toString();
    
  • 复用Map对象:将hmap和sortedMap移到循环外,每次循环clear()后复用,避免重复创建:
    // 在extractData开头初始化
    Map<String,String> hmap = new HashMap<>();
    Map<String,String> sortedMap = new TreeMap<>();
    
    // 循环内
    hmap.clear();
    // ... 填充hmap
    sortedMap.clear();
    sortedMap.putAll(hmap);
    
  • 提前缓存列信息:把列名、列类型移到循环外缓存,避免每行调用rsmd方法:
    // 在extractData开头缓存
    String[] colNames = new String[columnCount];
    int[] colTypes = new int[columnCount];
    for (int j = 1; j <= columnCount ; j++) {
        colNames[j-1] = rsmd.getColumnName(j);
        colTypes[j-1] = rsmd.getColumnType(j);
    }
    
    // 循环内直接使用数组
    for (int j = 0; j < columnCount ; j++) {
        String colName = colNames[j];
        int coltype = colTypes[j];
        // ... 后续逻辑
    }
    

3. 修正ResultSet处理逻辑错误并优化

原代码中getDouble的处理存在逻辑错误,同时影响性能:

  • 修正NULL值判断:rs.getDouble会把数据库NULL返回0,必须用rs.wasNull()判断真实NULL:
    if(coltype == java.sql.Types.DOUBLE){
        Double colValeur = rs.getDouble(j+1);
        String valeur = rs.wasNull() ? "NULL" : colValeur.toString();
        hmap.put(colName, valeur);
    }else{
        String colValeur = rs.getString(j+1);
        colValeur = (colValeur == null || colValeur.isEmpty()) ? "NULL" : colValeur;
        hmap.put(colName, colValeur);
    }
    
  • 避免不必要的TreeMap排序:如果排序仅为生成cleAno,直接按缓存的列顺序拼接即可,无需转TreeMap节省排序时间。

4. 事务优化

将整个处理过程放入一个事务,或分批次提交事务,避免每次操作都开启/提交事务:

// 手动控制事务示例
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
    // 原extractData内的处理逻辑
    transactionManager.commit(status);
} catch (Exception e) {
    transactionManager.rollback(status);
    throw e;
}

内容的提问来源于stack exchange,提问作者sneck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 01:09:29