관리 메뉴

nkdk의 세상

iBatis정리 본문

My Programing/IBatis_ORM_FRAMEWORK

iBatis정리

nkdk 2009. 7. 13. 10:47

iBatis정리

 

참고 URL

http://highheat.egloos.com/4490219

 

[2008.08.20] resultClass="java.util.HashMap" 으로  Date 형식을 가져오면 yyyy-mm-dd 까지만 가져오고 시간짤림#

ibatis-sqlmap-2.3.0.jar 를 사용하고 있음

 

방법 1) sqlMapConfig.xml 에 추가 => 안됨

    <typeHandler callback="com.ibatis.sqlmap.engine.type.SqlTimestampTypeHandler" javaType="java.util.Date"/>

방법 2)

800px-CharConversion.png 

 

sqlMapCOnfig.xml에 추가

<typeHandler callback="com.sec.b2bi.utils.callback.DateTypeHandlerCallback" javaType="java.lang.Object" />

 

com.sec.b2bi.utils.callback.DateTypeHandlerCallback 소스

  1. public Object getResult(ResultGetter getter) throws SQLException {
        if (getter.getObject() != null && getter.getObject().getClass().getName().equals("java.sql.Date")) {
            return getter.getTimestamp();
        } else {
            return getter.getObject();
        }
    }

 

참고)

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)


[2008.07.29] Caused by: java.sql.SQLException: 데이터 크기가 해당 유형의 최대 크기보다 큽니다: 7891 (Clob 처리)#

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 드라이버를 최신으로 올려라

 

[2008.07.23] The content of elements must consist of well-formed character data or markup.  Query에 '<' 사용시 ##

1) CDATA로 감싸주는 방법

  1. <sqlMap>
  2. <selectid="iBatis">
        <![CDATA[
          SELECT * FROM IBATIS_DATA
          WHERE NO < 10
        ]]>
  3. </select>
  4. </sqlMap>
2) <를 &lt;로 치환하는 방법

  1. <sqlMap>


    <selectid="iBatis">


    SELECT * FROM IBATIS_DATA


    WHERE NO &lt; 10


    </select>


    </sqlMap>






[2008.07.03] parameterClass, resultClass 모두 HashMap으로 처리하던 중 CLOB를 읽으면 oracle.sql.CLOB@12ca580 이렇게 됨##

<result property="CONTENTS" column="CONTENTS" javaType="java.lang.String" jdbcType="CLOB"/>

VO로 받을 때도 필요함 없으면 Cause: java.sql.SQLException: ORA-06502: PL/SQL: 수치 또는 값 오류: 문자열 버퍼가 너무 작습니다 오류 발생


[2008.06.16] iBatis-Oracle, HashMap 사용시 컬럼을 소문자로 받아보자##

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 클래스를 수정하면된다.


[2008.06.11] 설정정보##

<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 중에 하나를 사용할 수 있는데 그 각각의 값은 다음과 같은 특징을 가진다.

  • JDBC - Connection commit()과 rollback()메소드를 통해 트랜잭션을 제어하기 위한 JDBC를 사용하게 된다.
  • JTA - 이 트랜잭션관리자는 SQL Maps가 다른 데이터베이스나 트랜잭션 자원을 포함하는 더욱 넓은 범위의 트랜잭션을 포함하도록 하는 JTA전역트랜잭션를 사용한다.
  • EXTERNAL - 이것은 개발자가 직접 트랜잭션을 관리할 때 사용하는 것으로 주로 분산 컴포넌트 기반 시스템 환경에서 컨테이너가 트랜잭션을 관리하는 경우에 사용된다.

dataSource 의 type속성 값은 SIMPLE, DBCP, JNDI 중에 하나를 사용할 수 있다. 이 값은 각각 iBATIS SimpleDataSource 커넥션 풀링, Jakarta DBCP, JNDI를 통한 데이터소스을 사용하게 한다.


[2008.06.11] SQLMaps를 사용하기 위한 객체 생성##

SQLMaps 를 사용하기 위해서 기본적으로 생성해줘야 하는 객체는 SqlMapClient 이다. 이 객체를 생성하기 위해서는 SQLMaps설정파일인 SqlMapsConfig.xml을 인자로 다음과 같이 코드를 작성하면 기본적으로 SQLMaps의 기능을 사용할 수 있는 SQLMapClient 객체가 생성된다. 이 소스는 getSqlMapConfig()라는 메소드이며 반환되는 객체는 이 문서에서 계속 사용된다.

  1. Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
    SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);


[2008.06.11] Paging 처리##


  1. 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)를 탐색할수 있는 데이터의 부분집합을 당신에게 가지도록 허락한다.


[2008.06.11] 두개이상의 테이블에 대한 조회 ##
  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
    <sqlMap namespace="Message">
    <resultMap id="get-message" class="message">
    <result property="id" column="id"/>
    <result property="subject" column="subject"/>
    <result property="content" column="content"/>
    <result property="hitCount" column="hitCount"/>
    <result property="logTime" column="logTime"/>
    </resultMap>
    <resultMap id="get-message-result" class="message" extends="get-message">
    <result property="user.id" column="user_id"/>
    <result property="user.password" column="password"/>
    <result property="user.nickName" column="nickName"/>
    <result property="comments" column="{id=id}" select="getCommentList" />
    </resultMap>
    <select id="getMessageList" resultMap="get-message-result">
    <![CDATA[
    select a.seq as id,
    a.subject as subject,
    a.content as content,
    a.user_id as user_id,
    a.hit_count as hitCount,
    a.log_time as logTime,
    b.password as password,
    b.nick_name as nickName
    from message a, userinfo b
    where a.user_id=b.user_id
    order by a.seq desc
    ]]>
    </select>
    <select id="getCommentList" parameterClass="comment" resultMap="get-comment-result">
    <![CDATA[
    select cu.seq as seq,
    cu.content as content,
    cu.log_time as logTime,
    cu.user_id as userId,
    cu.message_seq as messageSeq,
    cu.nick_name as nickName,
    cu.password as password,
    m.seq as mseq,
    m.subject as subject,
    m.content as mcontent,
    m.user_id as muserId,
    m.hit_count as hitCount,
    m.log_time as mlogTime
    from (select c.seq, c.content,
    c.log_time, c.user_id, c.message_seq,
    u.nick_name, u.password
    from comment c, userinfo u
    where c.user_id=u.user_id) cu, message m
    where cu.message_seq=m.seq
    and cu.message_seq=#id#
    order by cu.seq asc
    ]]>
    </select>
    </sqlMap>


만약에 두개 이상의 조회조건, 예를 들면 comment객체의 id값과 content값을 인자로 넘겨야 한다면 ,(콤마)를 구분자로 주어서 {id=id,content=content} 형태로 column값을 설정하고 받는 쪽 parameterClass는 "java.util.HashMap" 으로 한다.

[2008.06.10] Query 보기##

log4j.properties 를 다음과 같이 세팅한다.

log4j.rootLogger=ERROR, stdout # SqlMap logging configuration... log4j.logger.com.ibatis=DEBUG log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

http://www.sqlinform.com/ 에서 이쁘게 볼수 있다. (SQL Fomatter)

[2008.06.09] SQL 조합하기##

<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>


[2008.06.09] Dynamic Query##

사용법 예제)
<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>


SVN 정보 ###
  • http://svn.apache.org/repos/asf/ibatis/trunk/java/docs/
번역문서 ###
강좌및 관련작성문서###
관련툴###
  • SQL2iBatis
    - SQL문이 저장되어 있는 sql파일을 인자로 줘서 iBatis용 자바소스와 SQL Maps 맵핑 xml파일 생성하기
  • DDL2iBatis
    -DDL2iBatis 프로그램 압축파일

출처:http://dolhead.springnote.com/pages/1388984?print=1