로컬 윈도우 환경에서는 잘 돌아가는 녀석이, 서버(리눅스) 에만 올리면 "There is no result map named" 에러가 발생한다. 

구글신에게 물어봐도 답을 찾지 못했다. 결국 금요일 퇴근도 못하고 삽질 3시간 후 해결 .... ㅠㅠ

AAAA-sqlmap.xml

<sqlMap namespace="_AAAA">


    ....


    <resultMap id="myMapId" class="XXXX">

    ....

    </resultMap>


    ....


</sqlMap>

 
BBBB-sqlmap.xml

<sqlMap namespace="_BBBB">


    ....


    <select id="list" resultMap="_AAAA.myMapId" parameterClass="XXXX">

    ....

    </select>


    ....


</sqlMap>


이렇게 사용해야 될 경우에는 sqlmap 파일의 로딩순서에 유의해야 한다.

sqlmap-config.xml 파일에 수동으로 기능별 sqlmap 파일을 선언해 줄 경우에는 아래와 같이 AAAA-sqlmap.xml을 먼저 선언해줘야 한다.

<sqlMapConfig> 

    ....

    <settings enhancementEnabled="true" useStatementNamespaces="true"/> 

    <sqlMap resource="com/foo/AAAA-sqlmap.xml" /> 

    <sqlMap resource="com/foo/BBBB-sqlmap.xml" /> 

    ....

</sqlMapConfig> 



만약 스프링과 연동하여 sqlmap 파일을 자동으로 로딩해서 사용하고 있을 경우에는 아래와 같이 해주도록 한다.

<bean id="sqlMapClient"

    class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

    ....

    <property name="mappingLocations">

        <list>

            <value>classpath*:/com/foo/AAAA-sqlmap.xml</value>

            <value>classpath*:/com/foo/BBBB-sqlmap.xml</value>

            <value>classpath*:/com/others/**/*-sqlmap.xml</value>

        </list>

    </property>

    ....

</bean>




10g XE에서 잘 돌아가던 넘이 운영서버 환경에 올리자 CLOB 등록이 안된다.

iBatis 단독 사용 시 CLOB 넣기

sqlmap-config.xml

<typeHandler javaType="string" jdbcType="CLOB" callback="test.OracleClobStringTypeHandler"/>
 
<transactionManager type="JDBC">
    <dataSource type="SIMPLE">
        <property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver" />
        <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@xxxxx:1521:SID" />
        <property name="JDBC.Username" value="${ID}" />
        <property name="JDBC.Password" value="${PASS}" />
    </dataSource>
</transactionManager>

logic-sqlmap.xml

INSERT INTO TABLE_NAME (
    SEQ, TITLE, CONTENTS
)
VALUES(
    #seq#, #title#, #contents:CLOB#
)

iBatis + Spring단독 사용 시 CLOB 넣기

application-context.xml

<bean id="dataSource"
    class="org.springframework.jndi.JndiObjectFactoryBean">
   <property name="jndiName" value="java:comp/env/jdbc/jndiNameDS"/>
</bean>

<bean id="sqlMapClient"
    class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
    <property name="configLocation" value="WEB-INF/conf/sqlmap-config.xml" />
    <property name="dataSource" ref="dataSource" />
    <property name="lobHandler"><ref bean="oracleLobhandler"/></property>
</bean>

<bean id="nativeJdbcExtractor"
    class="org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor"
    lazy-init="true" />

<bean id="oracleLobhandler"
    class="org.springframework.jdbc.support.lob.OracleLobHandler"
    lazy-init="true">
    <property name="nativeJdbcExtractor">
        <ref local="nativeJdbcExtractor" />
    </property>
</bean>

sqlmap-config.xml

<typeHandler
    callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"
    jdbcType="CLOB" javaType="java.lang.String" />

logic-sqlmap.xml

INSERT INTO TABLE_NAME (
    SEQ, TITLE, CONTENTS
)
VALUES(
    #seq#, #title#, #contents:CLOB#
)

java.lang.NullPointerException at org.springframework.jdbc.support.lob.OracleLobHandler.initOracleDriverClasses(OracleLobHandler.java:150
) 에러 발생 시


application-context.xml

JNDI -> DBCP로 변경
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
     <property name="driverClassName" value="oracle.jdbc.OracleDriver" />
     <property name="url" value="jdbc:oracle:thin:@xxxx:1521:SID" />
     <property name="username" value="${ID}" />
     <property name="password" value="${PASS}" />
     <parameter name="maxActive" value="20" />
     <parameter name="maxIdle" value="5" />
     <parameter name="maxWait" value="5000" />
     <property name="validationQuery" value="SELECT 1 FROM DUAL" />
</bean>

Oracle JDBC 드라이버는 ojdbc14.jar (최신버전)으로 적용.

http://opensource.atlassian.com/confluence/oss/display/IBATIS/Environment+Specific+Information

Timeout
As of release 2.2.0, iBATIS includes a query timeout funcionality.
You can specify both a global timeout
  
<settings defaultStatementTimeout="2" />
or a per query timeout
  
<statement ... timeout="2">
When the timeout expires, it throws a SQL Exception "ORA-01013 : user requested cancel of currentoperation".
  
Tested with: Oracle 9i release 2 drivers.

결론 : 수행에 3초이상 걸리는 쿼리가 있다면 해당 쿼리 정의문에 timeout attribute를 주던가 기본 sqlmap-config.xml 파일의 defaultStatementTimeout 값을 늘려주어라.

파라메타 클래스 정보에 null 값이 설정되어 전달될 경우 오라클 9i 버전대 JDBC 드라이버에서 위 에러 발생

해결
1. com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap 클래스의 setParameter() 메소드 수정

if (value == null) {
    value = "";
}

2. 오라클 JDBC 드라이버를 10 버전대 이상으로 업그레이드
객체타입이 아닌 기본자료형(int, long, etc..)에 대해서 SELECT의 결과가 비어있으면(null) 발생한다.

해결방법
1. 기본형은 초기화를 직접 해주거나 ....
2. NVL(COLUMN, 0) AS column 해주거나 ....
3. 해당 자료를 객체형으로 바꾸면 된다.

방식 1


방식 2

※ 추가 참고사항
케이스
메소드명
결과세트를 반환할 때
queryForList(), queryForObject()
한 개 이상의 결과 객체를 반환할 때
queryForList()
한개의 결과 객체를 반환할 때
queryForObject()
결과세트를 반환하지 않거나 OUT
파라미터에 결과세트를 세팅하지 않을 때
update()
 

xxxxDao.java 에서 ....
List tempList = new ArrayList();
tempList.add("1001");
tempList.add("1002");

new HashMap().put("listId", tempList);

xxxx-sqlmap.xml 에서 ....
<select id="someList" resultClass="someBean" parameterClass="java.util.Map">
.... 생략 ....
AND SAMPLE_CD IN
<iterate prepend="" property="listId" open="(" close=")" conjunction=", ">
    #listId[]#
</iterate>

※ 참고
prepend - the statement에 붙을 오버라이딩 가능한 SQL부분 (옵션)
property - 반복되기 위한 java.util.List타입의 프로퍼티 (필수)
open - 반복의 전체를 열기 위한 문자열, 괄호를 위해 유용하다. (옵션)
close - 반복의 전체를 닫기 위한 문자열, 괄호를 위해 유용하다. (옵션)
conjunction - 각각의 반복 사이에 적용되기 위한 문자열, AND 그리고 OR을 위해 유용하다. (옵션)

+ Recent posts