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

Java方法性能优化咨询:循环单查数据库导致性能低下

循环单查数据库的性能优化方案

当前代码在遍历Iterator时,对每个符合条件的FatturaArticoli对象单独执行一次数据库查询,频繁的数据库交互是性能瓶颈的核心原因。以下是针对性的优化方案:

1. 批量查询替代循环单查

将所有需要查询的商品ID收集后一次性从数据库获取,把N次数据库请求减少为1次,这是最有效的优化手段。

修改settaArticoliPreSalvataggio方法

先收集所有符合条件的商品ID和对应对象,再批量查询组装结果:

public List<ArticoliDett> settaArticoliPreSalvataggio(Iterator iteratore){
    try{
        List<Integer> articoloIds = new ArrayList<>();
        List<FatturaArticoli> validArticoli = new ArrayList<>();
        
        // 第一步:收集有效ID和对应对象
        while(iteratore.hasNext()){
            Object obj = iteratore.next();
            if(obj instanceof FatturaArticoli){
                FatturaArticoli articoloF = (FatturaArticoli) obj;
                if(articoloF.getIsLavoro() != null && articoloF.getIsLavoro())
                    continue;
                String codice = articoloF.getCodiceArticolo();
                if(!codice.equalsIgnoreCase("-")  
                        && !codice.equals(WFConst.COD_RITENUTA_ACCONTO)
                        && !codice.equals(WFConst.CODICE_IBAN)){
                    try {
                        int id = Integer.parseInt(codice);
                        articoloIds.add(id);
                        validArticoli.add(articoloF);
                    } catch (NumberFormatException e) {
                        log.logStackTrace(e);
                        return null;
                    }
                }
            }
        }
        
        // 第二步:批量查询所有商品数据
        if(articoloIds.isEmpty()){
            return new ArrayList<>();
        }
        Map<Integer, ArticoliDett> articoloMap = modelManager.getArticoliManager()
                .estraiArticoliCompletoBatch(articoloIds, false);
        
        // 第三步:组装结果列表
        List<ArticoliDett> listaArticoliPre = new ArrayList<>();
        for(FatturaArticoli articoloF : validArticoli){
            int id = Integer.parseInt(articoloF.getCodiceArticolo());
            ArticoliDett articoloPre = articoloMap.get(id);
            if(articoloPre == null){
                return null;
            }
            if(articoloF.getNomeArticolo().contains("(Articolo Gratuito)")){
                articoloPre.setNomeArticolo(articoloPre.getNomeArticolo() + " (Articolo Gratuito)");
            }
            listaArticoliPre.add(articoloPre);
        }
        
        return listaArticoliPre;
    }catch(Exception e){
        log.logStackTrace(e);
        return null;
    }
}

新增批量查询方法estraiArticoliCompletoBatch

在ArticoliManager中实现批量查询逻辑,使用IN子句一次性获取所有数据:

public Map<Integer, ArticoliDett> estraiArticoliCompletoBatch(List<Integer> idArticoli, Boolean estraiArticoloPerFornitore){
    Map<Integer, ArticoliDett> articoloMap = new HashMap<>();
    if(idArticoli.isEmpty()){
        return articoloMap;
    }
    
    // 构建IN子句占位符
    StringBuilder placeholders = new StringBuilder();
    for(int i=0; i<idArticoli.size(); i++){
        if(i > 0){
            placeholders.append(",");
        }
        placeholders.append("?");
    }
    
    String query = "SELECT CODARTICOLO,nomearticolo,soglia,prezzomedio,"
            + "quantita,prezzoattuale,prezzorivenditore, "
            + "prezzoingrosso,iva,quantitacartone,quantitaPedane, " 
            + "IN_SCHEDA_LAVORO, IS_LAVORO "
            + "FROM VISTAARTICOLI "
            + "WHERE codarticolo IN (" + placeholders + ")";
    
    // 用try-with-resources自动关闭资源,避免泄漏
    try (PreparedStatement stmt = db.prepareStatement(query)) {
        // 设置参数
        for(int i=0; i<idArticoli.size(); i++){
            stmt.setInt(i+1, idArticoli.get(i));
        }
        
        try (ResultSet rs = stmt.executeQuery()) {
            while(rs.next()) {   
                ArticoliDett articolo = new ArticoliDett();
                int nColumn = 1;
                int codArticolo = rs.getInt(nColumn++);
                articolo.setCodArticolo(codArticolo);
                articolo.setNomeArticolo(rs.getString(nColumn++));
                articolo.setSoglia(rs.getInt(nColumn++));
                articolo.setPrezzoMedioVendita(rs.getDouble(nColumn++));
                
                Articoli artGiacenza = new Articoli();
                artGiacenza.setCodArticolo(codArticolo);
                artGiacenza.setQuantita(rs.getInt(nColumn++));
                artGiacenza.setPrezzoAttuale(rs.getDouble(nColumn++));
                artGiacenza.setPrezzoRivenditore(rs.getDouble(nColumn++));
                artGiacenza.setPrezzoIngrosso(rs.getDouble(nColumn++));
                artGiacenza.setIva(rs.getInt(nColumn++));
                artGiacenza.setPezziCartone(rs.getInt(nColumn++));
                artGiacenza.setPezziPedana(rs.getInt(nColumn++));
                artGiacenza.setNomeArticolo(articolo.getNomeArticolo());
                artGiacenza.setInSchedaLavoro(rs.getInt(nColumn++) == 1);
                artGiacenza.setIsLavoro(rs.getInt(nColumn++) == 1);
                
                articolo.setArticoloGiacenze(artGiacenza);
                if(estraiArticoloPerFornitore){
                    articolo.getArticoloGiacenze().setArticoliFornitore(estraiArticoliPerFornitore(codArticolo));
                }
                
                articoloMap.put(codArticolo, articolo);
            }
        }
    } catch (Exception e) { 
        log.logStackTrace(e);
    }
    return articoloMap;
}

2. 优化原单查方法的细节

即使保留单查逻辑,也可以做以下优化提升效率:

  • 使用try-with-resources自动关闭资源:避免ResultSet、PreparedStatement未正确关闭导致的资源泄漏
  • 修正空结果处理:原方法不管是否查到数据都返回new ArticoliDett(),改为无数据时返回null,让调用方能正确判断查询结果
  • 检查索引:确保视图VISTAARTICOLI的codarticolo字段有索引,这能极大提升单条查询的速度
  • 简化布尔值转换:rs.getInt(nColumn++) == 1 ? true : false可简化为rs.getInt(nColumn++) == 1

优化后的原单查方法:

public ArticoliDett estraiArticoloCompleto(int idArticolo, Boolean estraiArticoloPerFornitore){
    String query = "SELECT CODARTICOLO,nomearticolo,soglia,prezzomedio,"
            + "quantita,prezzoattuale,prezzorivenditore, "
            + "prezzoingrosso,iva,quantitacartone,quantitaPedane, " 
            + "IN_SCHEDA_LAVORO, IS_LAVORO "
            + "FROM VISTAARTICOLI "
            + "WHERE codarticolo=?";
    
    try (PreparedStatement stmt = db.prepareStatement(query)) {     
        stmt.setInt(1, idArticolo);
        try (ResultSet rs = stmt.executeQuery()) {   
            if(rs.next()) {   
                ArticoliDett articolo = new ArticoliDett();
                int nColumn = 1;
                int codArticolo = rs.getInt(nColumn++);
                articolo.setCodArticolo(codArticolo);
                articolo.setNomeArticolo(rs.getString(nColumn++));
                articolo.setSoglia(rs.getInt(nColumn++));
                articolo.setPrezzoMedioVendita(rs.getDouble(nColumn++));
                
                Articoli artGiacenza = new Articoli();
                artGiacenza.setCodArticolo(codArticolo);
                artGiacenza.setQuantita(rs.getInt(nColumn++));
                artGiacenza.setPrezzoAttuale(rs.getDouble(nColumn++));
                artGiacenza.setPrezzoRivenditore(rs.getDouble(nColumn++));
                artGiacenza.setPrezzoIngrosso(rs.getDouble(nColumn++));
                artGiacenza.setIva(rs.getInt(nColumn++));
                artGiacenza.setPezziCartone(rs.getInt(nColumn++));
                artGiacenza.setPezziPedana(rs.getInt(nColumn++));
                artGiacenza.setNomeArticolo(articolo.getNomeArticolo());
                artGiacenza.setInSchedaLavoro(rs.getInt(nColumn++) == 1);
                artGiacenza.setIsLavoro(rs.getInt(nColumn++) == 1);
                
                articolo.setArticoloGiacenze(artGiacenza);
                if(estraiArticoloPerFornitore){
                    articolo.getArticoloGiacenze().setArticoliFornitore(estraiArticoliPerFornitore(codArticolo));
                }
                return articolo;
            }
        }
    } catch (Exception e) { 
        log.logStackTrace(e);
    }
    // 无数据时返回null,而非空对象
    return null;
}

3. 额外优化建议

  • 缓存常用商品数据:如果部分商品频繁被查询,可以引入本地缓存(如Guava Cache)或分布式缓存,避免重复查询数据库
  • 提前过滤无效数据:在收集ID阶段就排除格式错误的codiceArticolo,减少无效查询
  • 常量复用:将"(Articolo Gratuito)"定义为常量,避免重复创建字符串对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:37:06