본문 바로가기

Java

[Mybatis] ResultHandler로 대용량 Excel Download (POI)

대용량의 데이터를 데이터베이스에서 읽어 Excel로 다운로드 할 때 OOM(Out Of Memory)가 자주 발생한다.

OOM을 해결하기 위해서 Mybatis를 사용하는 경우에는 ResultHandler를 이용하여 각각의 Result에 대해 Excel의 Row를 생성하면 OOM 발생을 방지할 수 있다.

(기존의 DAO를 사용하지 않는 이유는 ResultHandler를 사용해서 데이터베이스에서 행을 패치하면서 바로 엑셀 생성을 처리하기 위해서임)

 

SqlSession session = sqlSessionFactory.openSession();

ResultHandler 를 이용하여 row별로 처리할때는 첫번째로 session을 열어줘야한다.

 

class InnerResultHandler implements ResultHandler {
      @Override
      public void handleResult(ResultContext resultContext) {
          Map data = new HashMap(); 

          try {
              Object obj = (Object) resultContext.getResultObject();
              Field[] fields = obj.getClass().getDeclaredFields(); // reflect 써서 entity => hashMap 변경

              for(int i=0; i<=fields.length-1;i++){ 
                  fields[i].setAccessible(true); 
                  data.put(fields[i].getName(), fields[i].get(obj));
              } 
          } catch (IllegalArgumentException e) {
              e.printStackTrace();
          } catch (IllegalAccessException e) {
              e.printStackTrace();
          } 
      }
  }

  try {
      session.select(pkgId, param, new InnerResultHandler());
  } catch(Exception e) {
      logger.error("Sql Session Exception : {}", e);

  } finally {
      session.close();
  }

 

따로 Class를 만들어도 되지만 지금은 Inner Class로 빼는게 보기에도 직관적이어서 위 처럼 하였다.

 

아래는 엑셀 완성본이다.

public void exportExcel(HttpServletResponse response, Map param, String pkgId, int workbookNum) {

	CreateExcelWrapper excel = new CreateExcelWrapper();
    
try {
    	excel.init( response, workbookNum, fileName, sField, sHeaderName, loginId, excelPath);
        excel.open();
        excel.createSheet();
		
        SqlSession session = sqlSessionFactory.openSession();
        
        class InnerResultHandler implements ResultHandler {
            @Override
            public void handleResult(ResultContext resultContext) {
                Map data = new HashMap(); 
                try {
                    Object obj = (Object) resultContext.getResultObject();
                    Field[] fields = obj.getClass().getDeclaredFields(); // reflect 써서 entity => hashMap 변경

                    for(int i=0; i<=fields.length-1;i++){ 
                        fields[i].setAccessible(true); 
                        data.put(fields[i].getName(), fields[i].get(obj));
                    } 
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } 
                excel.createBody(data);
            }
        }

          try {
              session.select(pkgId, param, new InnerResultHandler());
          } catch(Exception e) {
              logger.error("Sql Session Exception : {}", e);

          } finally {
              session.close();
          }
        
} catch(Exception e) {
	logger.error("Create Excel Wrapper Exception : {}", e);
} finally {
	excel.close();
    logger.info("Excel End ==========================");
}	
}

'Java' 카테고리의 다른 글

JWT 검증  (0) 2022.04.19
File Upload  (0) 2022.02.07
Menu Children 만들기  (0) 2019.10.17
Lombok 설치하기  (0) 2019.06.20