* 아이바티스는 DB의 ARRAY 타입을 사용하기 위해서는 사용자 정의 타입 핸들러를 정의하여 사용하여야 한다. String[] 과 Integer[] 의 TypeHandler 에 대해서 해 보았다.
lib - commons-lang-2.4.jar
ojdbc14.jar
ibatis-2.3.4.726.jar
log4j-1.2.14.jar
1. 우선 DB에 Type 을 설정
create or replace type VarrTel AS TABLE OF VARCHAR2(20);
create or replace type VarrType AS TABLE OF NUMBER;
- create or replace type 으로 선언할 시에는 NUMBER 이나 VARCHAR2(20) 이런식으로 꼭 명시를 해줘야 한다.
2. 간단한 PL/SQL Function 을 만들었다. ( 4개의 IN 파라미터와 1개의 OUT 파라미터가 있다. 간단하게 FOR LOOP 를 돌면서 INSERT 하는 내용이다. )
create or replace function for_test (
pi_guid IN TB_DATA_CARD_TEL.guid%TYPE,
pi_TelCount IN NUMBER,
pi_arrTel IN VarrTel,
pi_arrTelType IN VarrType,
pi_out OUT NUMBER
) return number IS
vRet number;
BEGIN
FOR vCount IN 1..pi_TelCount LOOP
INSERT INTO tb_data_card_tel
(
GUID, TEL_SEQ, PREFERENCE, TEL_TYPE, TEL_NUMBER
)
VALUES
(
pi_guid, sq_tel_seq.NEXTVAL, '2', pi_arrTelType(vCount), pi_arrTel(vCount)
);
END LOOP;
commit ; <-- 요놈 빼먹었다가...DB반영 안댔었다는 엄청난 삽질을 알았다....뭥미-_-;;;
pi_out := pi_TelCount;
RETURN PI_OUT ;
EXCEPTION
WHEN NO_DATA_FOUND THEN
pi_out:=1;
DBMS_OUTPUT.PUT_LINE('자료 없다');
return -1 ;
WHEN VALUE_ERROR THEN
pi_out:=2;
DBMS_OUTPUT.PUT_LINE('제약오류');
return -2 ;
WHEN OTHERS THEN
pi_out:=3;
DBMS_OUTPUT.PUT_LINE('기타에러');
return -3 ;
END;
3. iBATIS 의 TypeHandlerCallback 을 구현한 CallBackHandler 이다. ( String[] )
public class CallBackHandler implements TypeHandlerCallback {
static {
JdbcTypeRegistry.setType("VARRTEL", OracleTypes.ARRAY);
<-- "VARRTEL" 이 대문자다. 오라클은 대소문자 구별이 없다. 섞어쓰면....안 된 다-_-;
};
public void setParameter(ParameterSetter setter, Object parameter)
throws SQLException {
String[] strArr = (String[]) parameter; <-- Integer[] 는 요기랑 몇군데만 고치면 된다-_-;;;
setter.getPreparedStatement().getConnection();
Connection conn = setter.getPreparedStatement().getConnection();
ArrayDescriptor stringArrayDescriptor = ArrayDescriptor
.createDescriptor("VARRTEL", conn);
ARRAY valArray;
try {
valArray = new ARRAY(stringArrayDescriptor, conn, strArr);
} catch (SQLException e) {
throw e;
}
setter.setArray(valArray);
}
public Object getResult(ResultGetter getter) throws SQLException {
Array arr = getter.getArray();
if (arr == null)
return null;
else
return (String[]) arr.getArray();
}
public Object valueOf(String arg0) {
String[] r = new String[1];
r[0] = arg0;
return r;
}
}
4. iBATIS SqlMapConfig.xml 설정 내용이다
<sqlMapConfig>
<typeHandler callback="handler.CallBackHandler" javaType="[Ljava.lang.String;" />
<typeHandler callback="handler.IntegerCallBackHandler" javaType="[Ljava.lang.Integer;" />
-- typeHandler 등록은 꼭 가장 위에 써야 한다....안그러면 이빠이 에러가 뜬다...-_
-- "[Ljava.lang.String;" 이런것들은 참조형 타입이다.
<transactionManager type="JDBC" commitRequired="false">
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver" />
<property name="JDBC.ConnectionURL"
value="jdbc:oracle:thin:@" />
<property name="JDBC.Username" value="" />
<property name="JDBC.Password" value="" />
</dataSource>
</transactionManager>
<sqlMap resource="Account.xml" />
</sqlMapConfig>
5. 실제 PL/SQL Function 호출부분이다.
<typeAlias alias="data_card" type="DataCard" />
<parameterMap class="data_card" id="cardProc">
<parameter property="procRet" javaType="java.lang.Long" jdbcType="NUMERIC" mode="OUT" />
<parameter property="guid" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN" />
<parameter property="tel_count" javaType="java.lang.Long" jdbcType="NUMERIC" mode="IN" />
<parameter property="arrTel" jdbcType="VARRTEL" typeName="VARRTEL" javaType="[Ljava.lang.String;" typeHandler="handler.CallBackHandler" mode="IN" />
<parameter property="arrTelType" jdbcType="VARRTYPE" typeName="VARRTYPE" javaType="[Ljava.lang.Integer;" typeHandler="handler.IntegerCallBackHandler" mode="IN" />
<parameter property="procRet" javaType="java.lang.Long" jdbcType="NUMERIC" mode="OUT" />
</parameterMap>
<procedure id="updateDataCard" parameterMap="cardProc">
{? = call for_test(?,?,?,?,?) }
</procedure>
......OUT 파라미터 2개가 동일하단거에 딴지 걸지 말자....그냥 구차나서-_-;a
구냥 테스트코드-_-;
DECLARE
VRET NUMBER ;
V_OUT NUMBER := 0 ;
BEGIN
VRET := FOR_TEST('A200908111427000000000000871', 3, V_OUT ) ;
END ;
한가지더...
톰캣을 물려서 사용할 경우....
톰캣에서 타입을 톰캣에 맞춰 변화시킨다. 그렇기 때문에 위의 내용처럼 할 경우 톰캣의 타입을 가져오는 것이므로 DB와 ClassCastException 이 발생 한다.
org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor - Tomcat
org.springframework.jdbc.support.nativejdbc.WebSphereNativeJdbcExtractor - WebSphere
org.springframework.jdbc.support.nativejdbc.WebLogicNativeJdbcExtractor - WebLogic
org.springframework.jdbc.support.nativejdbc.C3P0NativeJdbcExtractor - C3P0
org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor - Common DBCP
요놈들 갖고 놀면 된다.....
Spring 2.5.6 + Tomcat 5.5.27 + iBATIS ibatis-2.3.4.726 + PL/SQL
에서 하다가...알게된 사실이다..
ARRAY 타입을 사용하기 위하여...
후아...