개요
프레임워크 내에서 대용량 데이터를 처리하고자 하는데 처음에는 통째로 Select 한 내용을 insert 하려고 했다.
INSERT INTO TABLE
SELECT COL1, COL2, COL3, ...
FROM TABLE2
...
이런식으로 진행하려고 했는데, 이는 당연히 문제를 낳을 수 있는 방식이었다.
해당 select의 용량이 메모리보다 크게 될 경우 OOM(Out Of Memory) Exception을 유발하게 되는 것이다.
따라서 Row 하나씩 Select 후 Insert를 foreach 나 Java 로직 내 For문을 통해 구현하려고 하였다.
해당 방법보다도 성능적으로 우수한 Ibatis(또는 Mybatis)에서 제공하는 옵션이 있었다. RowHandler(Mybatis에서는 ResultHandler) 를 통한 방식이었다.
RowHandler는 기본적으로 데이터를 Row 단위로 Fetch 하면서 메모리적으로 안정성을 보장받을 수 있다.
물론 OOM이 안나는 한계 내에선 기존 통째로 가져오는 방식의 성능이 당연히 우수하다. 그럼에도 최적의 Fetch 크기를 통해서 어느 정도 타협점을 찾아낼 순 있겠지만 그래도 애초에 DB에 대해 분할적으로 접근하기에 성능이 떨어진다.
(참고 : https://okky.kr/article/497304)
RowHandler를 활용한 대용량 데이터 Select
먼저 RowHandler 추상 클래스를 상속받는 Handler 클래스를 생성한다.
com.exe.service.impl.handler
import com.ibatis.sqlmap.client.event.RowHandler;
...
public Class TestRowHandler implements RowHandler{
public List<TestVO> testList = null;
public TestRowHandler(List<TestVO> testList) {
this.testList = testList;
}
// Row 단위별 처리 로직
public void handleRow(Object rowObject){
try{
TestVO testVO = (TestVO)rowObject;
testList.add(testVO);
}catch(Exception e){
e.printStackTrace();
}
public List<TestVO> getReturnList(){
return testList;
}
}
com.exe.service.impl.DAO
...
public List<testVO> selectQuery(Obejct param){
TestRowHandler testRowHandler = new TestRowHandler();
sqlSession.select("Job.selectQuery", param, testRowHandler);
List<testVO> returnList = testRowHandler.getReturnList;
return returnList;
}
해당 소스코드를 통해 데이터를 Row별로 처리가 가능하다.
ResultHandler를 활용해서 select한 대용량 데이터를 Row 단위로 insert 실행하기
com.exe.service.impl
public class testServiceImpl<testVO> implements testService {
...
@Resource(name = "testDAO")
private TestDAO testDAO;
public void selectUsrListWithHandler() throws Exception {
// resultHandler 익명 클래스
ResultHandler rsltHndlr = new ResultHandler<Object>(){
public void handleResult(ResultContext<?> context) {
// 처리 로직
TestVO testVO = (TestVO) context.getResultObject();
// LOGGER.info("DEBUG" + test);
// 삽입 처리
try{
testDAO.insertUsrList(testVO);
} catch (Exception e){
LOGGER.error("ResultHandler testVO 삽입 처리 실패 ");
}
}
};
testDAO.selectTstList(rsltHndlr);
}
}
serviceImpl 내에서 resultHandler를 상속받는 익명클래스를 구현한다
com.exe.service.impl.DAO
...
public void selectTstList(ResultHandler<?> rsltHndlr) throws Exception {
super.getSqlSession().select("testMapper.selectTstList", rsltHndlr);
}
해당 소스코드를 통해 데이터를 Row별로 처리가 가능하다.
'Web Programming > Spring' 카테고리의 다른 글
Eclipse 자동 Build 안됨 에러 (0) | 2020.08.08 |
---|---|
SVN LOCK / BUSY 트러블 슈팅 (0) | 2020.08.03 |
EJB(Enterprise Java Bean) (3) | 2020.07.02 |