Query Service - Pagination

Query 서비스를 통해 조회 유형의 쿼리문 실행 시 전체 결과를 조회하지 않고 해당 페이지에 속한 데이터만 조회할 수 있으므로, 효율적이고 성능에 유리하다. Query 서비스는 페이징 처리를 위해 별도의 로직이나 특정 DB에 종속적인 쿼리문을 요구하지 않는다. 다만 조회하고자 하는 페이지의 번호와 한 페이지에 보여지는 데이터의 개수만 입력 parameter로 전달하면 된다.

Query 서비스 속성 정의 파일 Sample

다음은 Query 서비스를 정의한 applicationContext-query-common.xml 과 Query 서비스에서 읽어들일 매핑 XML 파일의 위치를 정의한 applicationContext-query-sqlloader.xml 파일의 일부이다. (* 조회 유형의 쿼리에 대해 페이징 처리를 수행하기 위해서는 해당 DB에 맞는 PagingSQLGenerator를 추가 셋팅해주어야 함에 유의하도록 한다.)
<bean id="queryService" class="anyframe.core.query.impl.QueryServiceImpl">
	<property name="jdbcTemplate" ref="jdbcTemplate"/>
	<property name="sqlRepository" ref="sqlLoader"/>
	<property name="pagingSQLGenerator" ref="pagingSQLGenerator"/>
	<!-- 중략 -->
</bean>
<bean id="jdbcTemplate" class="anyframe.core.query.impl.jdbc.PagingJdbcTemplate">
  <property name="dataSource" ref="common_datasource" />
</bean>  
<bean id="pagingSQLGenerator" class="anyframe.core.query.impl.jdbc.generator.OraclePagingSQLGenerator"/>
<!-- 중략 -->

<bean name="sqlLoader" class="anyframe.core.query.impl.config.loader.SQLLoader">
   	<config:configuration>
 		    <filename>
 		      classpath:/services/query/mappings/mapping-pagination-query.xml
 		    </filename>
 		    <!-- 중략 -->
	</config:configuration>		
</bean> 
<!-- 중략 -->

매핑 XML 파일 Sample

다음은 앞서 정의한 Query 서비스를 통해 로드된 mapping-pagination-query.xml 로, 테이블 매핑 정보와 쿼리문을 포함하고 있다.
<query id="selectUsingPagination">
	<statement>
		SELECT NAME FROM TBL_CUSTOMER WHERE SSNO like ?
	</statement>
	<param type="VARCHAR" />
	<result class="integration.anyframe.core.query.vo.CustomerVO"/>
</query>

Query 서비스 테스트 코드 Sample

다음은 앞서 언급한 매핑 XML 파일에 정의된 SELECT 쿼리문을 실행하는 소스 코드 QueryServiceTestPagination.java 로, 페이징 처리된 수행 결과를 얻어 내기 위한 테스트 로직을 포함하고 있다.
/**
 * SELECT 수행 결과를 특정 페이지별로 조회하는 테스트 코드
 * 이 메소드에서는 TBL_CUSTOMER 테이블에 여러 데이터가 입력되었을 때, 한 페이지에 표현하고자 하는 데이터의 개수(5)와 
 * 조회 페이지 페이지 번호(3)를 입력하여  특정 페이지에 속한 데이터만 조회해 본다. 
 */
public void testSelectQuery() throws Exception {
	IQueryService queryService = (IQueryService) context
			.getBean("queryService");
	
	/** findWithRowCount() : 매핑 XML 파일에 정의되어 있는 query id를 이용하여 SELECT를 실행한다.
	 *                       findWithRowCount()는 한번의 호출로 해당 SELECT로 얻을 수 있는 전체 
	 *                       데이터의 개수와 특정 페이지에 해당하는 결과값들을 얻어 올 수 있다.
	 */
	HashMap resultMap = queryService.findWithRowCount("selectUsingPagination",
			new Object[] { "%1234%" }, 3, 5);
			
	CustomerVO customerVO = new CustomerVO();
	Map rsMap = new HashMap();
	// 특정 페이지에 속한 결과값들 추출
	List resultList = (List) resultMap.get(IQueryService.LIST);
	for(int i = 0 ; i < resultList.size() ; i ++){
		customerVO = (CustomerVO)resultList.get(i);
		customerVO.getNm();
	}  
	// 해당 SELECT로 얻어질 수 있는 전체 데이터의 개수 추출
	int totalSize = ((Long) resultMap.get(IQueryService.COUNT)).intValue();
	if (resultList.size() != 5 || totalSize != 15) {
		throw new Exception("Select query failed");
	}
}
다음은 Query 서비스에서 제공하는 페이징 처리 기능을 사용하기 위해서 알아두어야 할 사항들이다.
public Collection find...(..., int pageIndex, int pageSize);
  1. 페이지 번호가 1보다 작으면 결과 데이터가 없다. (Anyframe Core 3.3.0 이후)
  2. 페이지 번호가 1보다 작으면 첫번째 페이지가 조회된다. (Anyframe Core 3.2.0 이전)
  3. 한 페이지에 보여줘야 하는 데이터의 개수는 0보다 커야 한다.
  4. 페이지 번호와 한 페이지에 보여줘야 하는 데이터의 개수를 사용하여 계산한 값이 전체 결과 데이터의 개수보다 크면 결과 데이터가 없다.(Anyframe Core 3.3.0 이후)
  5. 페이지 번호와 한 페이지에 보여줘야 하는 데이터의 개수를 사용하여 계산한 값이 전체 결과 데이터의 개수보다 크면 마지막 페이지가 조회된다. (Anyframe Core 3.2.0 이전)
  6. 한 페이지에 보여줘야 하는 데이터의 개수가 생략될 경우 매핑 XML 파일의 <result>에 별도로 정의해 주어야 한다.

  7. <query id="selectUsingPagination" isDynamic="false">
    	<statement>
    		SELECT NAME FROM TBL_CUSTOMER WHERE SSNO like ?
    	</statement>
    	<param type="VARCHAR" />
    	<result length="10" class="integration.anyframe.services.query.vo.CustomerVO"/>
    </query>
앞서 소개된 샘플 테스트 코드를 포함하여 Query 서비스 소개 페이지에서 제공하는 모든 샘플 테스트 코드는 HSQL DB를 기반으로 실행된다. ( 단, ※ CallableStatement, LOB의 경우는 Oracle 9i, 10g를 기반으로 함. )

Resources

  • 다운로드
  • 샘플 테스트 코드를 포함하고 있는 anyframe-querytest-src.zip 파일을 다운받은 후, 테스트 환경 설정 을 참조하여 위에서 제시한 예제 코드를 실행해 볼 수 있다.
    Name
    Download
    anyframe-querytest-src.zip
    Download