读大文件内存溢出

读大文件内存溢出

  1. 读取大批量文件入库时的报错 java.lang.OutOfMemoryError:GC overhead limit exceeded
  2. 最终发现是读单个大文件报错 java.lang.OutOfMemoryError: Java heap space
  3. 每3000条插入一次 速度太慢 改端口再启动一个程序同时跑另一个文件夹 同时多次请求造成多线程同时执行

解决方法 -> 循环读文件时 每3000条提交一次后清空list 就不会有那么多fp对象积压在内存里了

private String handlerOneFile(File file) {
    StringBuilder err = new StringBuilder();
    try {
      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
      BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));
      // 用50M的缓冲读取文本文件
      BufferedReader reader = new BufferedReader(
              new InputStreamReader(fis, StandardCharsets.UTF_8),50*1024*1024);

      String row;
      List<CarLineFp> fpList = new ArrayList<>();
      int num = 0;
      while((row = reader.readLine()) != null){
        String[] split = row.split(",");
        CarLineFp fp = new CarLineFp();
        fp.setCarPlace(split[0].substring(0, 1));
        fp.setCarId(split[0].substring(1));
        fp.setPositionTime(LocalDateTime.parse(split[1], formatter));
        fp.setLongitude(split[2]);
        fp.setLatitude(split[3]);
        fp.setCarSpeed(split[4]);
        fp.setIndCode(split[5]);
        fp.setDirectionAngle(split[6]);
        fp.setCarStateSign(split[7]);
        fp.setRegionCode(split[8]);

        fpList.add(fp);
        num++;
        System.out.println("计数 ---> "+ num);
        // 3000条时候先提交一次
        if(fpList.size() == 3000){
          System.out.println("*******进入提交3000条");
          addBatch(fpList);
          System.out.println("*******提交3000条成功");
          fpList.clear();
        }
      }
      // 提交3000条的余数
      addBatch(fpList);
      log.info("*****************************"+file.getName() +" 行数 --> "+ num);
      reader.close();
    }catch (Exception e) {
      log.error(file.getName()+" 报错 --> "+e.getMessage());
      err.append(file.getName()).append(" 报错 --> ").append(e.getMessage());
    }

    return err.toString();
  }

再次更换思路优化 使用copy命令 效率显著提高 不过要先过滤一次重叠行的数据(加换行符或者删除)

copy wjy.car_line_fp_for_copy from 'E:\Desktop\TestProject\car\m08d07\new.txt' with csv

由于文件和数据库不在同一个服务器上 直接from文件行不通 需要通过文件流的方式,并且使用copyManager

不过需要自己新建connect,不能用mybatis

private void addWithIO(Connection connection, String full) throws Exception{
  FileInputStream fileInputStream = null;
  String sql = "COPY yanjiu.car_line_fp FROM STDIN WITH CSV";
  try {
    CopyManager copyManager = new CopyManager((BaseConnection) connection);
    // full 是完整文件路径
    fileInputStream = new FileInputStream(full);
    copyManager.copyIn(sql, fileInputStream);
  } finally {
    if(fileInputStream != null) {
      try {
        fileInputStream.close();
      }catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}
posted @ 2024-08-07 10:59  Wenenenenen  阅读(17)  评论(0编辑  收藏  举报