Springboot+poi 를 사용 하여 백만 급 데 이 터 를 업로드 하고 처리 합 니 다 EXCEL

10970 단어 SpringbootpoiEXCEL
1 Excel 업로드
엑셀 업로드 에 대해 서 는 비교적 일반적인 방법 을 사용 하 는데 사실은 파일 업로드 와 같다.구체 적 인 소스 코드 는 다음 과 같다.

  @PostMapping(value = "", consumes = "multipart/*", headers = "content-type=multipart/form-data")
  public Map<String, Object> addBlacklist(
      @RequestParam("file") MultipartFile multipartFile, HttpServletRequest request
  ) {
    //            
    String fileName = multipartFile.getOriginalFilename();
    if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
      return returnError(0,"          ");
    }
 
    String file = saveFile(multipartFile, request);
    int result = 0;
    try {
      result = blacklistServcice.addBlackLists(file);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return returnData(result);
  }
 
  private String saveFile(MultipartFile multipartFile, HttpServletRequest request) {
    String path;
    String fileName = multipartFile.getOriginalFilename();
    //       
    String realPath = request.getSession().getServletContext().getRealPath("/");
    String trueFileName = fileName;
    //     Excel     
    path = realPath + trueFileName;
    File file = new File(path);
    if (file.exists() && file.isFile()) {
      file.delete();
    }
    try {
      multipartFile.transferTo(new File(path));
    } catch (IOException e) {
      e.printStackTrace();
    }
 
    return path;
  }
위의 소스 코드 에서 우 리 는 saveFile 방법 을 볼 수 있 습 니 다.이 방법 은 파일 을 서버 로 컬 에 저장 하 는 것 입 니 다.이렇게 하면 후속 파일 내용 의 읽 기 에 편리 하고 모든 내용 을 한 번 에 읽 지 않 아 도 대량의 메모 리 를 소모 할 수 있 습 니 다.물론 여기 더 좋 은 방법 이 있 으 면 댓 글로 알려 주세요.
2 Excel 처리 도구 원본 코드

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
 
import java.io.InputStream;
import java.sql.SQLException;
import java.util.*;
 
/**
 * XSSF and SAX (Event API)
 */
public abstract class XxlsAbstract extends DefaultHandler {
  private SharedStringsTable sst;
  private String lastContents;
  private int sheetIndex = -1;
  private List<String> rowlist = new ArrayList<>();
  public List<Map<String, Object>> dataMap = new LinkedList<>(); //           
  public int willSaveAmount; //        
  public int totalSavedAmount; //         
  private int curRow = 0;    //   
  private int curCol = 0;    //     
  private int preCol = 0;    //      
  private int titleRow = 0;  //   ,      0
  public int rowsize = 0;  //  
 
  //excel       , sheet  ,            , sheet         ,   String  
  public abstract void optRows(int sheetIndex, int curRow, List<String> rowlist) throws SQLException;
 
  //     sheet,  sheetId     sheet  , 1  ,1-3
 
  /**
   * @param filename
   * @param sheetId sheetId     sheet  , 1  ,1-3
   * @throws Exception
   */
  public void processOneSheet(String filename, int sheetId) throws Exception {
    OPCPackage pkg = OPCPackage.open(filename);
    XSSFReader r = new XSSFReader(pkg);
    SharedStringsTable sst = r.getSharedStringsTable();
 
    XMLReader parser = fetchSheetParser(sst);
 
    // rId2 found by processing the Workbook
    //    rId#   rSheet#   sheet
    InputStream sheet2 = r.getSheet("rId" + sheetId);
    sheetIndex++;
    InputSource sheetSource = new InputSource(sheet2);
    parser.parse(sheetSource);
    sheet2.close();
  }
 
  public XMLReader fetchSheetParser(SharedStringsTable sst)
      throws SAXException {
    XMLReader parser = XMLReaderFactory.createXMLReader();
    this.sst = sst;
    parser.setContentHandler(this);
    return parser;
  }
 
  public void endElement(String uri, String localName, String name) {
    //   SST                   
    try {
      int idx = Integer.parseInt(lastContents);
      lastContents = new XSSFRichTextString(sst.getEntryAt(idx))
          .toString();
    } catch (Exception e) {
 
    }
 
    // v =>      ,          v          SST    
    //         rowlist ,                
    if (name.equals("v")) {
      String value = lastContents.trim();
      value = value.equals("") ? " " : value;
      int cols = curCol - preCol;
      if (cols > 1) {
        for (int i = 0; i < cols - 1; i++) {
          rowlist.add(preCol, "");
        }
      }
      preCol = curCol;
      rowlist.add(curCol - 1, value);
    } else {
      //        row ,       ,   optRows()   
      if (name.equals("row")) {
        int tmpCols = rowlist.size();
        if (curRow > this.titleRow && tmpCols < this.rowsize) {
          for (int i = 0; i < this.rowsize - tmpCols; i++) {
            rowlist.add(rowlist.size(), "");
          }
        }
        try {
          optRows(sheetIndex, curRow, rowlist);
        } catch (SQLException e) {
          e.printStackTrace();
        }
        if (curRow == this.titleRow) {
          this.rowsize = rowlist.size();
        }
        rowlist.clear();
        curRow++;
        curCol = 0;
        preCol = 0;
      }
    }
  }
}
3 분석 성공 후 데이터 처리
먼저 우 리 는 소스 코드 를 보 여 준 후에 구체 적 으로 설명 할 것 이다.

public int addBlackLists(String file) throws ExecutionException, InterruptedException {
    ArrayList<Future<Integer>> resultList = new ArrayList<>();
    XxlsAbstract xxlsAbstract = new XxlsAbstract() {
 
      //         
      @Override
      public void optRows(int sheetIndex, int curRow, List<String> rowlist) {
 
        /**
         *                8000,    8000,
         *       
         */
        if (this.willSaveAmount == 5000) {
 
          //    
          List<Map<String, Object>> list = new LinkedList<>(this.dataMap);
          Callable<Integer> callable = () -> {
            int count = blacklistMasterDao.addBlackLists(list);
            blacklistRecordMasterDao.addBlackListRecords(list);
            return count;
          };
          this.willSaveAmount = 0;
          this.dataMap = new LinkedList<>();
          Future<Integer> future = executor.submit(callable);
          resultList.add(future);
        }
 
        //    
        Map<String, Object> map = new HashMap<>();
        map.put("uid", rowlist.get(0));
        map.put("createTime", rowlist.get(1));
        map.put("regGame", rowlist.get(2));
          map.put("banGame", rowlist.get(2));
        this.dataMap.add(map);
        this.willSaveAmount++;
        this.totalSavedAmount++;
      }
    };
    try {
      xxlsAbstract.processOneSheet(file, 1);
    } catch (Exception e) {
      e.printStackTrace();
    }
 
    //             
    if(xxlsAbstract.willSaveAmount != 0){
      List<Map<String, Object>> list = new LinkedList<>(xxlsAbstract.dataMap);
      Callable<Integer> callable = () -> {
        int count = blacklistMasterDao.addBlackLists(list);
        blacklistRecordMasterDao.addBlackListRecords(list);
        return count;
      };
      Future<Integer> future = executor.submit(callable);
      resultList.add(future);
    }
 
    executor.shutdown();
    int total = 0;
    for (Future<Integer> future : resultList) {
      while (true) {
        if (future.isDone() && !future.isCancelled()) {
          int sum = future.get();
          total += sum;
          break;
        } else {
          Thread.sleep(100);
        }
      }
    }
    return total;
  }
위의 소스 코드 에 대해 우 리 는 읽 은 EXCEL 데 이 터 를 데이터베이스 에 삽입 해 야 한 다 는 것 을 알 수 있 습 니 다.여기 서 데이터베이스 의 IO 를 줄 이 고 삽입 효율 을 높이 기 위해 우 리 는 5000 개의 일괄 삽입 을 사용 합 니 다(주의:데이터 양 이 너무 많 으 면 구 성 된 SQL 문 구 를 실행 할 수 없습니다).
최종 실행 에 성공 한 삽입 결 과 를 얻 고 삽입 실행 이 느 려 야 합 니 다.자바 다 중 스 레 드 를 사용 한 Future 모드 는 비동기 방식 으로 최종 적 으로 J 실행 결 과 를 가 져 옵 니 다.
위의 실현 을 통 해 건물 주 테스트 에서 최종 백만 개의 데 이 터 를 얻 는 데 4 분 정도 걸 리 면 해결 할 수 있다.더 좋 은 방법 이 있다 면 댓 글 을 남 겨 주세요.
추가 지식:Java API SXSSFWorkbook Excel 대량 데이터 내 보 내기(백만 급)시간 초과 해결
이전에 간단 한 HSSFWorkbook 을 사용 하면 내 보 낸 데 이 터 를 초과 할 수 없습니다.

나중에 SXSSFWorkbook 으로 바 뀌 면 더 많은 것 을 내 보 낼 수 있 습 니 다.하지만...
그리고 제 이전 코드 는 모든 데 이 터 를 한꺼번에 찾 아 냈 고 몇 십 만 건 이 시간 을 초 과 했 습 니 다.
이전 코드 는 모든 결 과 를 한꺼번에 찾 아 냈 고 list 에는 수 십 만 개의 데이터 가 저장 되 어 있 었 다.기능 설계 의 문제 로 인해 나의 이 인 터 페 이 스 는 세 가지 기능 을 동시에 처리 해 야 한다.

게다가 SQL 조회 효율 문제 로 요청 시간 이 초과 되 었 습 니 다.
지금 은 더 많은 데 이 터 를 얻 기 위해 최 적 화 를 선택 할 수 밖 에 없다.최적화 조회 의 sql 은 여기 서 말 하지 않 고 내 보 내기 기능 의 최적화 만 말 합 니 다.
사실은 일괄 처리 조회 결과 입 니 다.

이렇게 하면 조회 속도 가 빨 라 지고 패 키 징 속도 도 빨 라 지 며 전체 속도 가 빨 라 지면 시간 초과 가 발생 하지 않 는 다 는 것 이 장점 이다.또한 페이지 별로 찾 아 낸 결 과 를 list 에 넣 으 면 JVM 메모리 가 너무 큰 상황 이 발생 하지 않 는 다.메모리 가 넘 쳐 시스템 이 무 너 지 는 것 을 피하 십시오.
다시 최적화:
위 에서 이렇게 하면 내 보 낼 수 있 지만 코드 가 아름 답지 않 습 니 다.

이렇게 하면 훨씬 간결 해 보인다.
경험 증,조회 패 키 징 EXCEL 7000 개 데이터 처리 1 초



이 글 은 Springboot+poi 를 사용 하여 백만 급 데 이 터 를 업로드 하고 처리 합 니 다.EXCEL 은 편집장 이 여러분 에 게 공유 한 모든 내용 입 니 다.참고 하 시기 바 랍 니 다.여러분 들 도 많이 응원 해 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기