| jdbcTemplate | DataSource 서비스를 이용하여 해당하는 DB에 접근하고, 정의된 쿼리문을 실행시키는 역할을 수행하는 PagingJdbcTemplate의 Bean Id를 정의한다. | ||
| sqlRepository | 테이블 매핑 정보 및 쿼리문을 정의한 매핑 XML 파일들을 처리하는 역할을 수행하는 SQLLoader의 Bean Id를 정의한다. | ||
| pagingSQLGenerator | DB에 특화된 형태의 페이징 처리를 위한 SQL을 구성하지 않더라도, 해당 DB에 따라 페이징 처리를 위해 알맞은 SQL을 생성할 수 있도록 도와주는 PagingSQLGenerator의 Bean Id를 정의한다. | ||
| lobHandler | LOB 유형의 데이터를 다루어야 하는 경우 알맞은 LobHandler의 Bean Id를 정의한다. | ||
| velocityPropsFilename | Dynamic SQL 문을 다루어야 하는 경우 Velocity에 의해 남겨지는 Log 파일의 경로를 변경하고자 할 때
정의한다. Velocity Log 파일의 경로는 다음과 같이 절대/상대 경로(file:...)나 클래스패스(classpath:...)를
이용하여 정의 가능하다.
* 해당하는 경로에 지정된 로그 파일이 생성되어 있어야 함에 유의하도록 한다. |
| dataSource | 참조할 dataSource service의 Bean Id를 정의한다. | ||
| exceptionTranslator | ExceptionTranslator의 Bean Id를 정의한다. ExceptionTranslator는 DB 데이터 조작시 SQLException이 발생한 경우 별도 Exception 객체에 해당하는 SQL Error Code와 Error Message 정보를 셋팅하여 throw하도록 하는 역할을 수행하며, Query 서비스에서는 anyframe.core.query.impl.util.RawSQLExceptionTranslator를 제공하고 있다. 따라서, ExceptionTranslator를 별도 셋팅하면, 데이터 조작으로 인한 오류가 발생한 경우 Query 서비스에서 throw한 QueryServiceException으로부터 SQL Error Code와 Error Message 정보를 추출할 수 있게 된다. |
||
| maxFetchSize | 다량의 데이터 전체 조회시 발생할 수 있는 성능 저하를 방지하기 위해, maxFetchSize를 활용할 수 있다. 조회된 결과 데이터의 건수가 정의된 maxFetchSize보다 큰 경우 Exception 처리된다. | N | N/A |
| nativeJdbcExtractor | OraclePagingJdbcTemplate을 사용하는 경우에만 정의한다. 사용중인 Connection Pool에 맞게 Wrapping되어 있는 Connection 객체로부터 본래의 JDBC Connection 객체를 추출하는 역할을 수행하는 NativeJdbcExtractor의 Bean Id를 정의한다. | N | N/A |
| config:configuration | filename properties | ||||
| filename | 테이블 매핑 정보와 사용할 쿼리문을 정의하고 있는 파일명을 지정하는 요소로 복수 지정 가능하다. filename 요소에 대한 지정은 Spring Configuration 파일 경로 지정 방식과 동일하므로, 절대/상대적인 파일 경로 지정(file:...)과 클래스패스를 이용한 지정(classpath:...)이 가능하다. *를 활용한 Pattern Matching 역시 적용 가능하다. | ||||
| nullcheck | 해당 DB Column의 값이 없는 경우, null value가 리턴되었을 때, 지정한 값으로 변환시켜준다. 현재, CHAR, VARCHAR, LONGVARCHAR 타입의 칼럼에 대해서만 지원된다. | ||||
| sqlload | dynamic | 매핑 XML 파일에 대한 동적 Reload 설정여부를 정의한다. | |||
| frequency | Reload 주기를 세팅한다.(miliseconds 단위) 10미만 입력시 -> 10으로 인식하며, 10이상 입력시 -> 입력값으로 인식한다. | ||||
| skiperror | 매핑 XML 파일을 읽어들이면서, error가 발생한 경우 skip 여부를 셋팅한다. |
| DB 종류 | PagingSQLGenerator Class |
| Oracle | anyframe.core.query.impl.jdbc.generator.OraclePagingSQLGenerator |
| DB2 | anyframe.core.query.impl.jdbc.generator.DB2PagingSQLGenerator |
| HSQLDB | anyframe.core.query.impl.jdbc.generator.HSQLPagingSQLGenerator |
| Altibase | anyframe.core.query.impl.jdbc.generator.AltibasePagingSQLGenerator |
public class OraclePagingSQLGenerator extends AbstractPagingSQLGenerator {
public String getPaginationSQL(String originalSql, Object[] originalArgs,
int[] originalArgTypes, int pageIndex, int pageSize) {
// 정의된 기본 쿼리문을 ROWNUM을 이용한 형태로 변경하기 위해 앞,뒤로 문자열 추가
StringBuffer sql = new StringBuffer(
" SELECT * FROM ( SELECT INNER_TABLE.* , ROWNUM AS ROW_SEQ FROM ( \n");
sql.append(originalSql);
sql.append(" ) INNER_TABLE WHERE ROWNUM <= ? ) "
+ " WHERE ROW_SEQ BETWEEN ? AND ?");
// 쿼리문에 입력되어야 할 기본 입력 인자 외에
// 페이징 처리를 위한 pageIndex, pageSize 인자값 셋팅
setQueryArgs(originalArgs, pageIndex, pageSize);
// 쿼리문에 입력되어야 할 기본 입력 인자 외에
// 페이징 처리를 위한 pageIndex, pageSize 인자 타입 셋팅
setQueryArgTypes(originalArgTypes);
// 변경된 쿼리문 전달
return sql.toString();
}
protected void setQueryArgs(Object[] originalArgs, int pageIndex,
int pageSize) {
Object[] args = new Object[originalArgs.length + 3];
for (int i = 0; i < originalArgs.length; i++) {
args[i] = originalArgs[i];
}
args[originalArgs.length] = String.valueOf(new Long(pageIndex
* pageSize));
args[originalArgs.length + 1] = String.valueOf(new Long((pageIndex - 1)
* pageSize + 1));
args[originalArgs.length + 2] = String.valueOf(new Long(pageIndex
* pageSize));
setArgs(args);
}
protected void setQueryArgTypes(int[] originalArgTypes) {
int[] argTypes = new int[originalArgTypes.length + 3];
for (int i = 0; i < originalArgTypes.length; i++) {
argTypes[i] = originalArgTypes[i];
}
argTypes[originalArgTypes.length] = Types.VARCHAR;
argTypes[originalArgTypes.length + 1] = Types.VARCHAR;
argTypes[originalArgTypes.length + 2] = Types.VARCHAR;
setArgTypes(argTypes);
}
}
| nativeJdbcExtractor | 사용중인 Connection Pool에 맞게 Wrapping되어 있는 Connection 객체로부터 본래의 JDBC Connection
객체를 추출하는 역할을 수행하는 NativeJdbcExtractor의 Bean Id를 정의한다. (해당 lobHandler에서
nativeJdbcExtractor를 필요로 하는 경우에만 정의)
다음은 Spring에서 제공하는 주요 JdbcExtractor 클래스들이다. org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor org.springframework.jdbc.support.nativejdbc.C3P0NativeJdbcExtractor org.springframework.jdbc.support.nativejdbc.WebLogicNativeJdbcExtractor org.springframework.jdbc.support.nativejdbc.WebSphereNativeJdbcExtractor 오픈소스 프로젝트인 Commons DBCP를 Connection Pool로 채택한 경우 CommonsDbcpNativeJdbcExtractor를 사용할 수 있다. |
<bean id="oracle_queryservice" class="anyframe.core.query.impl.QueryServiceImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
<property name="sqlRepository" ref="sqlLoader"/>
<property name="pagingSQLGenerator" ref="pagingSQLGenerator"/>
<property name="lobHandler" ref="lobHandler"/>
<!-- if you don't define velocityPropsFilename,
queryservice doesn't make a velocity log file. -->
<property name="velocityPropsFilename" value="file:./testvelocity/velocity.log"/>
</bean>
<bean id="oracle_jdbcTemplate" class="anyframe.core.query.impl.jdbc.PagingJdbcTemplate">
<property name="dataSource" ref="oracle_datasource" />
</bean>
<bean id="pagingSQLGenerator"
class="anyframe.core.query.impl.jdbc.generator.OraclePagingSQLGenerator"/>
<bean id="nativeJdbcExtractor"
class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
lazy-init="true"/>
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler"
lazy-init="true">
<property name="nativeJdbcExtractor" ref="nativeJdbcExtractor"/>
</bean>
<bean id="sqlLoader" class="anyframe.core.query.impl.config.loader.SQLLoader">
<config:configuration>
<!-- xml files in folder -->
<!--filename>file:./testmappings/**/testcase-*.xml</filename-->
<!-- xml files in classpath -->
<filename>
classpath:/services/query/mappings/mapping-general-query.xml
</filename>
<!-- ... -->
<nullcheck type="VARCHAR" default-value="" />
<sqlload dynamic="true" frequency="5" />
<skiperror>true</skiperror>
</config:configuration>
</bean>
public void testInsertQuery() throws Exception{
IQueryService queryService = (IQueryService) context.getBean("queryService");
//create() : XML mapping파일에 정의되어 있는 SQL query를 이용하여 INSERT를 실행한다.
int rs = queryService.create("create", new Object[] { "1234567890123", "AAAAA" , "seoul"});
if ( rs == -1 ){
throw new Exception("Insert query failed");
}
}
public void testSelectQuery() throws Exception{
IQueryService queryService = (IQueryService) context.getBean("queryService");
//find() : XML mapping파일에 정의되어 있는 SQL query를 이용하여 SELECT를 실행한다.
//일반적인 경우(table과 class를 mapping하지 않은 경우)
ArrayList rsquery = (ArrayList) queryService
.find("selectGeneral", new Object[] { "%12345%" });
Map hsRsquery = new HashMap();
for( int i = 0 ; i < rsquery.size() ; i ++ ){
hsRsquery = (Map) rsquery.get(i);
String name = (String) hsRsquery.get("name");
}
/*매핑 XML에 해당 클래스와 매핑되는 테이블이 존재하지 않을 경우,
* 쿼리 수행 결과에 대해 하나의 Row별로 칼럼명,
* 해당값을 쌍으로 org.apache.commons.collections.map.ListOrderedMap에 put하고
* ListOrderedMap들을 ArrayList에 담은 형태로 결과값을 리턴하게 된다.
*/
//Table - Class mapping을 사용한 경우
Collection rsqueryNotUsingResultMapping = queryService
.find("selectNotUsingResultMapping", new Object[] { "%12345%" });
Iterator rsqueryItr = rsqueryNotUsingResultMapping.iterator();
while (rsqueryItr.hasNext()) {
CustomerVO customer = (CustomerVO) rsqueryItr.next();
String name = customer.getNm();
}
//result-mapping을 사용 한 경우
Collection rsqueryUsingResultMapping = queryService
.find("selectUsingResultMapping", new Object[] { "%12345%" });
Iterator rsqueryItr_01 = rsqueryUsingResultMapping.iterator();
while (rsqueryItr_01.hasNext()) {
CompositionCustomerVO compositionCustomer
= (CompositionCustomerVO) rsqueryItr_01.next();
String name = compositionCustomer.getCompositionName();
}
if( rsquery.size() != 1 ){
throw new Exception("Select query failed");
}
if( rsqueryNotUsingResultMapping.size() != 1 ){
throw new Exception("Select query failed");
}
if( rsqueryUsingResultMapping.size() != 1 ){
throw new Exception("Select query failed");
}
}
public void testUpdateQuery() throws Exception {
IQueryService queryService = (IQueryService) context
.getBean("queryService");
//update() : XML mapping파일에 정의되어 있는 SQL query를 이용하여 UPDATE를 실행한다.
int rs = queryService.update("update"
, new Object[] { "9999999999999", "AAAAA" , "busan" , "1234567890123"});
if ( rs == -1 ){
throw new Exception("Update query failed");
}
}
public void testDeleteQuery() throws Exception {
IQueryService queryService = (IQueryService) context
.getBean("queryService");
//remove() : XML mapping파일에 정의되어 있는 SQL query를 이용하여 DELETE를 실행한다.
int rs = queryService.remove("delete", new Object[] { "9999999999999" });
if ( rs == -1 ){
throw new Exception("Delete query failed");
}
}