프로그래머의 삶 Programmer's Life/PersistanceSolution

iBATIS TYPEHANDLER (Strnig[] , Integer[] )

Oliver's World 2009. 8. 12. 10:23
728x90


* 아이바티스는 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 타입을 사용하기 위하여...

후아...








728x90