Query Service - implements IResultSetMapper
일반적으로 Query 서비스는 매핑 XML 파일에 정의되어 있는 쿼리문을 실행한 후, 그 실행 결과를 <result/> 내에 정의된 객체나
HashMap에 담들을 이용하여 특정 쿼리문을 실행한다. 그런데 실행 결과를 <result/> 내에 정의된 객체에 담기 위해서는 Java Reflection
API 호출이 발생하므로 대량의 데이터를 처리할 때 성능이 저하된다. 또한 실행 결과를 HashMap에 담는 경우에는 Java Reflection API 호출없이,
칼럼명을 키값으로 하여 칼럼값을 셋팅하나 특정 메소드 호출을 통해 주고 받는 데이터가 명확히 식별되지 않게 되어 어플리케이션 분석 및 변경시 불리할 수 있다.
QueryService에서는 이러한 점을 보완하기 위해서 ResultSetMapper 실행을 지원한다. 즉, 쿼리문 실행 결과 처리를 Query 서비스에
위임하지 않고, 별도 정의된 ResultSetMapper를 통해 직접 처리할 수 있도록 한다.
Query 서비스 속성 정의 파일 Sample
다음은 Query 서비스를 정의한
applicationContext-query-common.xml
과
Query 서비스에서 읽어들일 매핑 XML 파일의 위치를 정의한
applicationContext-query-sqlloader.xml
파일의 일부이다.
<bean id="queryService" class="anyframe.core.query.impl.QueryServiceImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
<property name="sqlRepository" ref="sqlLoader"/>
<!-- 중략 -->
</bean>
<bean id="jdbcTemplate" class="anyframe.core.query.impl.jdbc.PagingJdbcTemplate">
<property name="dataSource" ref="common_datasource" />
</bean>
<!-- 중략 -->
<bean name="sqlLoader" class="anyframe.core.query.impl.config.loader.SQLLoader">
<config:configuration>
<filename>classpath:/services/query/mappings/mapping-resultsetmapper-query.xml</filename>
<!-- 중략 -->
</config:configuration>
</bean>
<!-- 중략 -->
매핑 XML 파일 Sample
다음은 앞서 정의한 Query 서비스를 통해 로드된
mapping-resultsetmapper-query.xml
로,
쿼리문을 포함하고 있다. Query Id가 findCustomerWithResultSetMapper인 쿼리문 실행 결과는 사용자가 정의한 integration.anyframe.services.query.CustomerMapper를 통해
처리되도록 정의하고 있음을 알 수 있다.
<queries>
<query id="findCustomerWithResultSetMapper" isDynamic="false">
<statement>select NAME, ADDRESS from TB_CUSTOMER where SSNO like ?</statement>
<param type="VARCHAR"/>
<result mapper="integration.anyframe.services.query.CustomerMapper"/>
</query>
</queries>
<result/>의 mapper는 신규 추가된 속성으로 http://www.anyframejava.org/dtd/anyframe-core-query-mapping-3.2.dtd에 정의되어 있다.
따라서, mapper를 정의하기 위해서 매핑 XML 파일 헤더에 DTD 위치를 다음과 같이 정의해 주어야 함에 유의하도록 한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE queryservice PUBLIC "-//ANYFRAME//DTD QUERYSERVICE//EN"
"http://www.anyframejava.org/dtd/anyframe-core-query-mapping-3.2.dtd">
<queryservice>
...
</queryservice>
ResultSetMapper 코드 Sample
사용자는 다음과 같은 순서로 ResultSetMapper를 구현하면 된다.
- Query 서비스에서 제공하는 인터페이스 anyframe.core.query.IResultSetMapper를 implements
- ResultSet을 입력 인자로 하는 콜백 메소드 mapRow() 정의
- maprRow() 메소드 내에서 ResultSet을 이용하여 원하는 객체에 실행 결과 셋팅 & return
다음은 앞서 언급한 매핑 XML 파일에 ResultSetMapper로써 정의된
CustomerMapper.java
의 일부이다.
public class CustomerMapper implements IResultSetMapper {
public Object mapRow(ResultSet resultSet) throws SQLException {
CustomerVO customer = new CustomerVO();
customer.setNm(resultSet.getString("name"));
customer.setAddr(resultSet.getString("address"));
return customer;
}
}
Query 서비스 테스트 코드 Sample
다음은 앞서 언급한 매핑 XML 파일에 정의된 SELECT 쿼리문을 실행하는 소스 코드
QueryServiceResultSetMapperTest.java
의
일부이다.
/**
* QueryService의 find() 메소드를 호출하여 매핑 XML에 정의된 쿼리문을 실행시키고, 매핑 XML에 정의된
* IResultSestMapper 유형의 Mapper를 이용하여, 결과값이 매핑되는지 체크하기 위한 테스트 코드
*/
public void testFindWithCustomResultSetMapper() throws Exception {
IQueryService queryService = (IQueryService) context
.getBean("queryService");
// execute query
Collection rtList = queryService.find(
"findCustomerWithResultSetMapper", new Object[] { "%123456%" });
// assert a size of result
if (rtList.size() != 3)
throw new Exception("Fail to select with custom ResultSetMapper.");
// assert in detail
Iterator resultItr = rtList.iterator();
while (resultItr.hasNext()) {
CustomerVO customer = (CustomerVO) resultItr.next();
if (!customer.getAddr().equals("Seoul"))
throw new Exception("Fail to compare result in defail.");
}
}
앞서 소개된 샘플 테스트 코드를 포함하여 Query 서비스 소개 페이지에서 제공하는 모든 샘플 테스트 코드는 HSQL DB를
기반으로 실행된다. ( 단, ※ CallableStatement, LOB의 경우는 Oracle 9i, 10g를 기반으로 함. )
Resources
다운로드
샘플 테스트 코드를 포함하고 있는 anyframe-querytest-src.zip 파일을 다운받은 후, 테스트 환경 설정
을 참조하여
위에서 제시한 예제 코드를 실행해 볼 수 있다.
| Name |
Download |
| anyframe-querytest-src.zip |
Download
|