[Google Apps Engine] JDO를 이용하여 Datastore를 사용하기
[Google Apps Engine] JDO를 이용하여 Datastore를 사용하기
바이너리 조건 속성
단일 조건 요소-단일 조건 요소는 특수한 조건을 위해 프로퍼티의 상태를 체크한다.
prepend | statement에 붙을 오버라이딩 가능한 SQL부분(옵션) |
property | 체크하기 위한 프로퍼티(필수) |
<isPropertyAvailable> | 프로퍼티가 유효한지 체크 (이를 테면 파라미터의 프로퍼티이다.) |
<isNotPropertyAvailable> | 프로퍼티가 유효하지 않은지 체크 (이를 테면 파라미터의 프로퍼티가 아니다.) |
<isNull> | 프로퍼티가 null인지 체크 |
<isNotNull> | 프로퍼티가 null이 아닌지 체크 |
<isEmpty> | Collection,문자열 또는 String.valueOf()프로퍼티가 null이거나 empty(“” or size() < 1)인지 체크 |
<isNotEmpty> | Collection,문자열 또는 String.valueOf()프로퍼티가 null이아니거나 empty(“” or size() < 1)가 아닌지 체크
사용법 예제) <isNotEmpty prepend="AND" property="firstName"> FIRST_NAME = #firstName# </isNotEmpty> |
다른 요소들
Parameter Present : 파라미터 객체가 존재하는지 체크
Parameter Present Attributes : prepend - the statement에 붙을 오버라이딩 가능한 SQL부분
<isParameterPresent> | 파라미터 객체가 존재(not null)하는지 체크 |
<isNotParameterPresent> | 파라미터 객체가 존재하지(null) 않는지 체크
사용법 예제) <isNotParameterPresent prepend="AND"> EMPLOYEE_TYPE = 'DEFAULT' </isNotParameterPresent> |
Iterate : 이 태그는 Collection을 반복하거나 리스트내 각각을 위해 몸체 부분을 반복한다.
Iterate Attributes :
prepend - the statement에 붙을 오버라이딩 가능한 SQL부분 (옵션)
property - 반복되기 위한 java.util.List타입의 프로퍼티 (필수)
open - 반복의 전체를 열기 위한 문자열, 괄호를 위해 유용하다. (옵션)
close - 반복의 전체를 닫기 위한 문자열, 괄호를 위해 유용하다. (옵션)
conjunction - 각각의 반복 사이에 적용되기 위한 문자열, AND 그리고 OR을 위해 유용하다. (옵션)
<iterate> | java.util.List 타입의 프로퍼티 반복 사용법 예제) <iterate prepend="AND" property="userNameList" open="(" close=")" conjunction="OR"> username = #userNameList[]# </iterate> 주의:iterator요소를 사용할 때 리스트 프로퍼티의 끝에 중괄호[]를 포함하는 것은 중요하다. 중괄호는 문자열처럼 리스트를 간단하게 출력함으로부터 파서를 유지하기 위해 리스트처럼 객체를 구별한다. |
http://highheat.egloos.com/4490219
ibatis-sqlmap-2.3.0.jar 를 사용하고 있음
방법 1) sqlMapConfig.xml 에 추가 => 안됨
<typeHandler callback="com.ibatis.sqlmap.engine.type.SqlTimestampTypeHandler" javaType="java.util.Date"/>
방법 2)
sqlMapCOnfig.xml에 추가
<typeHandler callback="com.sec.b2bi.utils.callback.DateTypeHandlerCallback" javaType="java.lang.Object" />
com.sec.b2bi.utils.callback.DateTypeHandlerCallback 소스
참고)
2000.12.05 00:00:00 <-- rs.getDate(1)
1970.01.01 14:52:17 <-- rs.getTime(1)
2000.12.05 14:52:17 <-- rs.getTimestamp(1)
Insert 시
insert into table values( #blobField:BLOB#, #clobField:CLOB#)
조회시
class를 HashMap을 사용할때는 javaType="java.lang.String" 을 추가한다.
<resultMap id="result" class="beanClassName">
<result property="clobField" column="clobField" jdbcType="CLOB"/>
<result property="blobField" column="blobField" jdbcType="BLOB"/>
</resultMap>
혹시 java.sql.SQLException: 소켓에서 읽을 데이터가 없습니다
라는 오류가 발생하면 JDBC 드라이버를 최신으로 올려라
1) CDATA로 감싸주는 방법
<sqlMap><selectid="iBatis">
<![CDATA[
SELECT * FROM IBATIS_DATA
WHERE NO < 10
]]></select></sqlMap>2) <를 <로 치환하는 방법
<sqlMap>
<selectid="iBatis">
SELECT * FROM IBATIS_DATA
WHERE NO < 10
</select>
</sqlMap>
<result property="CONTENTS" column="CONTENTS" javaType="java.lang.String" jdbcType="CLOB"/>
VO로 받을 때도 필요함 없으면 Cause: java.sql.SQLException: ORA-06502: PL/SQL: 수치 또는 값 오류: 문자열 버퍼가 너무 작습니다 오류 발생
iBatis-Oracle 사용시 질의의 결과값을 HashMap 표현으로 가져올 수 있다. 즉 다음과 같은 방법이다.
<select
id=”selectItems”
parameterClass=”java.util.Map”
resultClass=”java.util.HashMap”>
select id, name from item where id = #id#
</select>
위와 같이 사용하면, Struts의 DynaActionForm, JSTL의 Collection 처리 방법을 이용하여 매우 빠른 코딩 속도를 보여준다. 나같은 귀차니즘 개발자를 위해 탄생한것 같은 느낌까지 든다.
하지만 문제가 있으니.. HashMap에 표현된 키값이 모두 대문자라는 사실이다. Oracle에서의 질의 결과셋 Meta 정보가 그러하다고 한다. 소문자를 주로 사용하는 코딩 환경에서 컬럼명만 대문자로 써줘야 한다는 것은 정말 귀찮은 일이다.
방법이 없는것은 아니다. <select>에다 <resultMap>을 매핑해 주면 가능하다. 하지만 질의 개수만큼 매핑을 만들어 줘야 한다는것.. 귀찮다. -_-;; SQL문에서의 해결 방법(select id as “id”, name as “name”..) 또한 귀찮은 것은 마찬가지이다.
결국 발상을 전환해 Oracle JDBC Thin Driver를 변경하기로 했다. JAD의 도움을 받아 드라이버 내의 oracle.jdbc.dbaccess.DBColumn 클래스를 수정하면된다.
<settings>은 SQLMaps에서 사용되는 다양한 옵션과 최적화를 위한 값들이다. 각각의 값들은 다음의 표를 참조하길 바란다.
| cacheModelsEnabled | SqlMapClient 를 위한 모든 캐시모델을 가능 유무. Default: true (enabled) |
| enhancementEnabled | 런타임시 바이트코드 향상을 가능유무. Default: false (disabled) |
| lazyLoadingEnabled | 모든 늦은(lazy)로딩을 가능유무. Default: true (enabled) |
| maxRequests | 동시에 SQL문을 수행할 수 있는 쓰레드의 수. 셋팅값보다 많은 쓰레드는 다른 쓰레드가 수행을 완료할 때까지 블록 된다. Default: 512 |
| maxSessions | 주어진 시간동안 활성화될 수 있는 세션의 수. Default: 128 |
| maxTransactions | 한꺼번에 SqlMapClient.startTransaction()에 들어갈 수 있는 쓰레드의 최대갯수. 셋팅값보다 많은 쓰레드는 다른 쓰레드가 나올 때까지 블록 된다. Default: 32 |
| useStatementNamespaces | 이 셋팅을 가능하게 하면 당신은 sqlmap이름과 statement이름으로 구성된 전체적인 이름(fully qualified name)으로 맵핑된 statement를 참조해야 한다. 예를 들면: queryForObject("sqlMapName.statementName"); Default: false (disabled) |
<typeAlias>는 패키지 명을 포함한 클래스가 너무 길 때 각각의 SQLMaps맵핑 파일에서 사용하기 번거로우므로 별칭을 두어서 간단하게 사용할 수 있다. 하지만 미리 정의된 별칭이 있다. 그 값들은 다음과 같다.
transactionManager에서 사용되는 별칭
JDBC :
com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig
JTA :
com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig
EXTERNAL :
com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
dataSource에서 사용되는 별칭
SIMPLE
:com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory
DBCP
:com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory
JNDI :
com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory
< transactionManager>는 트랜잭션에 관련된 값을 셋팅하고 하위 데이터소스값을 지정하는 <dataSource>를 가진다. transactionManager의 type속성 값은 JDBC, JTA, EXTERNAL 중에 하나를 사용할 수 있는데 그 각각의 값은 다음과 같은 특징을 가진다.
dataSource 의 type속성 값은 SIMPLE, DBCP, JNDI 중에 하나를 사용할 수 있다. 이 값은 각각 iBATIS SimpleDataSource 커넥션 풀링, Jakarta DBCP, JNDI를 통한 데이터소스을 사용하게 한다.
SQLMaps 를 사용하기 위해서 기본적으로 생성해줘야 하는 객체는 SqlMapClient 이다. 이 객체를 생성하기 위해서는 SQLMaps설정파일인 SqlMapsConfig.xml을 인자로 다음과 같이 코드를 작성하면 기본적으로 SQLMaps의 기능을 사용할 수 있는 SQLMapClient 객체가 생성된다. 이 소스는 getSqlMapConfig()라는 메소드이며 반환되는 객체는 이 문서에서 계속 사용된다.
PaginatedList list = sqlMap.queryForPaginatedList("getContacts", 20);
while (true) {
Iterator listIterator = list.iterator();
while (listIterator.hasNext()) {
System.out.println(
((Contact)listIterator.next()).getContactId());
}
if( list.isNextPageAvailable())
list.nextPage();
elsebreak;
}
CONTACT 테이블이 1000레코드를 가지고 있고 유저를 위해 스페레드시트에서 이것을 표시할것을 원한다고 가정해보자. 하지만 한번에 50개의 레코드만 표시할수 있다. 이런 경우에 우리는 1000 contacts를 포함하는 ResultSet를 얻기위해 CONTACT테이블을 쿼리하길 원하지는 않는다. 우리는 CONTACT 테이블을 쿼리하길 원하고 한번에 50개의 레코드만 얻는다. SQLMaps는 이런 타입의 경우를 다루기 위해서 PaginatedList 인터페이스를 제공한다. 이것은 유저가 앞으로(forward) 그리고 뒤로(backward)를 탐색할수 있는 데이터의 부분집합을 당신에게 가지도록 허락한다.
만약에 두개 이상의 조회조건, 예를 들면 comment객체의 id값과 content값을 인자로 넘겨야 한다면 ,(콤마)를 구분자로 주어서{id=id,content=content} 형태로 column값을 설정하고 받는 쪽 parameterClass는 "java.util.HashMap" 으로 한다.
log4j.properties 를 다음과 같이 세팅한다.
http://www.sqlinform.com/ 에서 이쁘게 볼수 있다. (SQL Fomatter)
<sql id="select-order">
select * from order
</sql>
<sql id="select-count">
select count(*) as value from order
</sql>
<sql id="where-shipped-after-value">
<![CDATA[
where shipDate > #value:DATE#
]]>
</sql>
<select id="getOrderShippedAfter" resultClass="map">
<include refid="select-order" />
<include refid="whre-shipped-after-value" />
</select>
<select id="getOrderCountShipped-after-value" resultClass="int">
<include refid="select-count" />
<include refid="whre-shipped-after-value" />
</select>
사용법 예제)
<isNotEmpty prepend="AND" property="firstName">
FIRST_NAME = #firstName#
</isNotEmpty>
※ 가능 조건
<isPropertyAvailable> : 프로퍼티가 유효한지 체크
<isNotPropertyAvailable> : 프로퍼티가 유효하지 않은지 체크
<isNull> : 프로퍼티가 null인지 체크
<isNotNull> : 프로퍼티가 null이 아닌지 체크
<isEmpty> : Collection, 문자열 또는 String.valueOf() 프로퍼티가 null이거나 empty(“” or size() < 1)인지 체크
<isNotEmpty> : Collection, 문자열 또는 String.valueOf() 프로퍼티가 null 이아니거나 empty(“” or size() < 1)가 아닌지 체크
<isGreaterThan prepend="AND" property="id" compareValue="0">
<isEqual property="method" compareValue="howManyIssued" prepend="AND">
사용법 예제)
<isNotParameterPresent prepend="AND">
EMPLOYEE_TYPE = 'DEFAULT'
</isNotParameterPresent>
※ 가능 조건
<isParameterPresent> : 파라미터 객체가 존재(not null)하는지 체크
<isNotParameterPresent> : 파라미터 객체가 존재하지(null) 않는지 체크
사용법 예제)
<iterate prepend="AND" property="userNameList" open="(" close=")" conjunction="OR">
username = #userNameList[]#
</iterate>
IN 예제)
<delete id="deleteBoardAttach" parameterClass="com.sec.b2bi.model.BoardData">
delete from attach_data
where doc_id = #id#
<isNotNull prepend="and" property="attachIds">
id not in
<iterate property="attachIds" open="(" close=")" conjunction=",">
#attachIds[]#
</iterate>
</isNotNull>
</delete>
사용예)
<statement id="dynamicGetAccountList" resultMap="account-result" >
select * from ACCOUNT
<dynamic prepend="WHERE">
<isNotNull prepend="AND" property="firstName">
(ACC_FIRST_NAME = #firstName#
<isNotNull prepend="OR" property="lastName">
ACC_LAST_NAME = #lastName#
</isNotNull>
)
</isNotNull>
<isGreaterThan prepend="AND" property="id" compareValue="0">
ACC_ID = #id#
</isGreaterThan>
</dynamic>
order by ACC_LAST_NAME
</statement>