본문 바로가기

Web Programming/Spring

ibatis 대용량 처리 RowHandler(ResultHandler)

개요

프레임워크 내에서 대용량 데이터를 처리하고자 하는데 처음에는 통째로 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