如何优化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
相关产品推荐
相关产品推荐

