Site Search :
Standard Enterprise XML Methodology Pattern Setting Tunning Other
Article Contributors
GuestBook
Javapattern Maven
XSourceGen Dev
JetSpeed Test
JLook Image
jLook Family Site


JDBC DataConversion(Using Metadata)
 
다른 box의 데이터베이스의 테이블내역을 Metadata로서 이관할 수 있는 방법에 대하여 설명한다. ( 2003/04/24 ) 438
Written by ienvyou - 최지웅
1 of 1
 

자. 이번글을 왜 쓰게 되었는지의 이유를 또 설명한다. 항상 여기에 올라오는 아티클의 경우는
놀새가 실제 프로젝트에서 필요에 의하여 만들어지게 된 코드의 데이터화가 주 목적이기
때문이다.

얼마전에 EJB Container Manage의 xml configuration방법을 이용하여 데이터를 변환하는 프로그램을
작성한 적이 있었다. 
그 프로그램의 요지는 프로그램과 EJB CMP 필드간의 매핑을 통하여 데이터베이스 트랜잭션을
처리하는 것처럼 source table과 target table간의 데이터를 다른 형태의 컬럼으로 변경할 수 있도록
하는 것었다. 

지금 작성하여 아티클로 쓰게 된 프로그램은 우선 같은 구조(테이블명 및 컬럼명)를 가진 
테이블이 나란히 서로 다른 box에 존재할 경우 데이터를 이관하도록 하였다. 
"아니~ 놀새야~ PL-SQL은 호구로 있는감?" 하면서 딴지걸면 이렇게 대답하겠다.
"아니~ 두개가 같은 벤더의 데이터베이스만 될거라는걸 장담하쇼?" 라고..

전에 프로젝트에서 Sybase에서 Oracle로의 데이터컨버젼 및 이관작업에 2달이 걸렸다는 (내가 아무리
생각해보아도 rule만 정확히 정의된다면 1달이면 족히 끝났으리라 생각한다) 얘기를 들었다.
게다가 그 컨버젼을 담당한 사람들이 오로지 C만 할줄 아는 사람들이었는데, 그사람들이 자바API를
좀 더 자유자재로만 쓸 수 있었더라도 그런 시간낭비는 하지 않았으리라~
소위 엘리트의식에 존심이 하늘을 찌르는 S모 회사에서 말이다. 무슨 방법을 썼을까? 
Sybase Data -> SAM File -> File Read -> Conversion by rule -> Pro*C insert -> Oracle
거참..쩝쩝.. 

자바의 플랫폼 독립~! 예술이다~

또 이야기가 삼천포로 빠지려 한다. ^^

본론으로 들어가자. 

이글을 읽은 당신, 놀새는 동기부여를 위하여 당신에게 생각할 것을 주문한다. 
어떻게 하면 같은 한쪽 DB의 데이터를 다른쪽DB로 프로그램의 수정없이 계속 옮기게 할 수 있을까?

java.sql패키지를 이용할 것은 당연하고, 프로그램구동시의 입력을 테이블명만 줬을 경우
동작을 하게 한다면 sql패키지의 사용클래스는?

Connection, PreparedStatement, ResultSet 만 가지고는 할 수 없을 것이다. 그렇다면 추가적으로 
필요한것은 무엇인가?
바로 ResultSetMetaData인터페이스가 그 역할을 충실할 것이다.
테이블컬럼의 이름 및 개수, 타입등이 모두 들어있기 때문에 그러한 정보만 가지고서도 
해당 테이블에서 insert query문장을 추출해내는 것은 그리 어렵지 않은 일이기 때문이다.

http://java.sun.com/j2se/1.4.1/docs/api/java/sql/ResultSetMetaData.html

위의 내용을 참조하게 되면 대체 해당 인터페이스가 무엇을 하게 되는지를 알게 될것이다.

바로 코드를 보도록 하자. 


import java.sql.*;
import java.util.*;
public class DataConversion {
    public DataConversion(){}
    public void start(String tableName) {
        Connection tmp_conn = null;
        Connection abs_conn = null;
        PreparedStatement pstmt1 = null; // select pstmt
        PreparedStatement pstmt2 = null; // inser pstmt
        ResultSet rset = null;
        try{
            Class.forName("oracle.jdbc.driver.OracleDriver");
            String url = "jdbc:oracle:thin:@192.168.0.137:1521:abn";
            tmp_conn = DriverManager.getConnection(url, "abs_tmp", "abs_tmp");
            abs_conn = DriverManager.getConnection(url, "abn_new", "abn_new");
            abs_conn.setAutoCommit(false);
            StringBuffer query = new StringBuffer();
            query.append("select * from ").append(tableName);

            pstmt1 = tmp_conn.prepareStatement(query.toString());
            rset = pstmt1.executeQuery();

            ResultSetMetaData rsmd = null;
            int row = 0;
            int col = 0;
            rsmd = rset.getMetaData();
            //컬럼의 갯수를 가져온다.
            col = rsmd.getColumnCount();
            System.out.println("Number of Column = " + col);

            //배열을 초기화시킨다.
            String [] columnNames = new String[col];
            int [] columnTypes = new int[col];
            StringBuffer insertQuery = new StringBuffer(1024);
            insertQuery.append("insert into ").append(tableName).append("(");
            for(int i = 0 ; i < col ; i++){
                    columnNames[i] = rsmd.getColumnName(i+1);
                    columnTypes[i] = rsmd.getColumnType(i+1);
            }

            for(int i = 0 ; i < columnNames.length; i++) {
                insertQuery.append(columnNames[i]);
                if( i != columnNames.length - 1 ) insertQuery.append(",");
            }
            insertQuery.append(") values (");
            for(int i = 0 ; i < columnNames.length; i++) {
                insertQuery.append("?");
                if( i != columnNames.length - 1 ) insertQuery.append(",");
            }
            insertQuery.append(")");
            System.out.println(insertQuery.toString());

            pstmt2 = abs_conn.prepareStatement(insertQuery.toString());

            for(int i = 1 ; rset.next() ; i++){
                for(int j = 0 ; j < col ; j++){
                    switch (columnTypes[j]) {
                        case	Types.NUMERIC: 
                            pstmt2.setLong(j+1, rset.getLong(j+1));
                            break;
                        case	Types.VARCHAR: 
                            pstmt2.setString(j+1, rset.getString(j+1));
                            break;
                        case	Types.TIMESTAMP: 
                            pstmt2.setDate(j+1, rset.getDate(j+1));
                            break;
                        default:
                    }
                }
                
                pstmt2.addBatch();
                if( i % 10000 == 0) {
                    pstmt2.executeBatch();
                    System.out.println(i + "건 처리중 ");
                }
            }

            pstmt2.executeBatch();
            abs_conn.commit();
        }catch(Exception e) {
            try{
                abs_conn.rollback();
            }catch(Exception e2){}
            e.printStackTrace();
        }finally{
            try{
                rset.close();
                pstmt1.close();
                tmp_conn.close();
                abs_conn.close();
            }catch(Exception e1) {}
        }
    }

    public static void main(String [] args) {
        new DataConversion().start(args[0]);
    }
}

    
요즘 프로젝트 종료때문에 너무 바빠서 글을 자주 올리지 못함을 죄송하게 생각합니다.
 
1
References
 
Copyright ⓒ 2003 www.javapattern.info & www.jlook.com, an jLOOK co.,LTD