제3장 tbJDBC의 사용

내용 목차

3.1. 개발 과정
3.2. Connection Properties
3.3. 데이터 타입
3.4. tbJDBC Stream
3.4.1. 컬럼에 대한 Stream 생성
3.5. 내장 함수 호출
3.5.1. PSM의 사용
3.5.2. Java Stored Procedure의 사용
3.6. 예외 처리

본 장에서는 tbJDBC를 사용하여 애플리케이션 프로그램을 개발하는 과정을 순서대로 설명하고, 추가로 데이터 타입, Stream 등을 설명한다.

다음은 tbJDBC를 사용하여 애플리케이션 프로그램을 개발하는 과정이다.

  1. 패키지 import

    기본이 되는 Java 패키지와 tbJDBC 패키지를 import한다.

    /* 기본 Java 패키지 */
    import java.sql.*;
    
    /* tbJDBC 패키지 */
    import com.tmax.tibero.jdbc.*;
    import com.tmax.tibero.jdbc.ext.*;
  2. 데이터베이스 연결

    데이터베이스에 연결하기 위해서 Connection 객체를 생성한다. Connection 객체를 생성하기 위해서 tbJDBC를 로딩한 후 DriverManager를 이용한다.

    Class.forName("com.tmax.tibero.jdbc.TbDriver");
    Connection conn = DriverManager.getConnection
                     ("jdbc:tibero:thin:@localhost:8629:dbsvr",
                      "tibero", "tmax");

    또는 다음과 같이 java.util.Properties를 이용하여 Conneciton할 때 설정 정보를 설정할 수 있다.

    Class.forName("com.tmax.tibero.jdbc.TbDriver");
    Properties prop = new Properties();
    prop.setProperty("user", "tibero");
    prop.setProperty("password", "tmax");
    Connection conn = 
        DriverManager.getConnection("jdbc:tibero:thin:@localhost:8629:dbsvr", prop);

    또는 다음과 같이 DataSource 객체를 이용하여 Connection 객체를 생성한다.

    TbDataSource ds = new TbDataSource();
    ds.setURL("jdbc:tibero:thin:@localhost:8629:dbsvr");
    ds.setUser("tibero");
    ds.setPassword("tmax");
    Connection conn = ds.getConnection();
  3. Statement 객체 생성

    데이터베이스에 연결되면, Connection 객체를 이용하여 Statement 객체를 생성한다.

    Statement         stmt  = conn.createStatement();
    PreparedStatement pstmt = conn.prepareStatement("SELECT empno, name FROM emp");
    CallableStatement cstmt = conn.prepareCall("BEGIN ... END;");
  4. 질의문 수행과 ResultSet 객체 받기

    질의문을 수행하고 ResultSet 객체를 받는다.

    ResultSet rs = stmt.executeQuery("SELECT * FROM ALL_OBJECTS;");
  5. ResultSet 객체 처리

    ResultSet 객체는 next() 메소드를 이용하여 모든 로우에 접근할 수 있다. 이때 getXXX() 메소드를 호출하면 원하는 타입별로 로우 데이터를 가져올 수 있다. 만약 next() 메소드가 false라면, 더는 결과 집합이 존재하지 않음을 의미한다.

    while (rs.next())
    {
        System.out.println(rs.getString(1));
        System.out.println(rs.getInt(2));
    }
  6. 커밋 또는 롤백 수행

    기본적으로 DML 문(INSERT, UPDATE, DELETE)을 수행한 다음에는 자동으로 커밋된다. 이러한 기능을 auto-commit이라고 한다. 사용자는 Connection 클래스에서 제공하는 다음의 메소드를 이용하여 이 기능을 임의로 해제할 수 있다.

    void setAutoCommit(boolean flag)

    이 메소드를 이용하여 auto-commit 기능을 비활성화하면, 사용자는 반드시 DML 문을 사용한 다음 커밋이나 롤백을 수행해야 데이터베이스에 적용된다.

    conn.commit();
    conn.rollback();
  7. ResultSet 객체와 Statement 객체 소멸

    ResultSet 객체와 Statement 객체는 반드시 소멸시켜야 한다. 왜냐하면, tbJDBC 내부에는 별도의 finalizer 메소드가 없기 때문이다. 이 때문에 예상치 못한 시점에 심각한 메모리 누수 현상이 발생할 수 있고, 데이터베이스 내부 커서의 최대 허용 범위를 초과하여 에러가 발생할 수도 있다.

    rs.close();
    stmt.close();

  8. 데이터베이스 연결 해제

    마지막으로 모든 작업이 끝나면 반드시 데이터베이스 연결을 해제해야 한다. 그렇지 않으면 현재 세션이 연결된 상태로 남아 있기 때문에 다음 연결할 때에는 최대 허용 세션을 초과할 수 있다. 따라서 데이터베이스 연결에 실패할 수도 있다.

    conn.close();

다음은 DB를 연결할 때에 Properties로 설정할 수 있는 속성들이다.

속성명타입설명
databaseNameString서버에 존재하는 특정 데이터베이스의 이름이다.
dataSourceNameString데이터소스의 이름이다.
descriptionString데이터소스에 대한 설명이다.
networkProtocolString서버와 통신하는 네트워크 프로토콜의 이름이다. (기본값: TCP)
passwordString서버 접속을 위한 패스워드이다.
userString서버 접속을 위한 사용자 이름이다.
portNumberint서버 리스너의 포트 번호이다.
serverNameString데이터베이스의 이름이다.
login_timeoutint

소켓의 read timeout을 지정한다.

최소 소켓을 생성할 때부터 DB 연결 생성이 완료될 때까지 적용된다. DB 연결 생성이 완료된 뒤에는 read_timeout 속성이 적용된다. 만약 응답이 없이 지정된 시간이 지나면 timeout을 발생시키지만 설정값이 0일 경우에는 timeout을 발생시키지 않는다. (단위: millisecond, 기본값: 0)

read_timeoutint

DB 연결 생성이 완료된 이후의 소켓의 read timeout을 지정한다.

만약 응답이 없이 지정된 시간이 지나면 timeout을 발생시키지만 설정값이 0일 경우에는 timeout을 발생시키지 않는다.

(단위: millisecond, 기본값: 0)

charactersetString

JDBC에서 인코딩, 디코딩 Character Set을 지정한다.

(기본값: 서버의 문자 셋을 사용)

program_nameString프로그램 이름이다. (기본값: JDBC Thin Client)
includeSynonymsStringDatabaseMetaData.getColumn()에서 synonyms 객체를 포함할지 여부를 지정한다. (기본값: false)
mapDateToTimestampStringDATE 컬럼에 대해서 결과 타입으로 Timestamp(true)로 돌려줄지 Date(false)로 여부를 지정한다. (기본값: true)
defaultNCharStringPreparedStatement.setString() API로 설정한 문자열을 national charset 설정을 이용하여 서버로 전송하도록 강제한다. (기본값: false)
self_keepaliveString

SELF KEEP ALIVE 기능을 활성화할지 여부를 지정한다.

활성화한 경우에는 self_keepidle, self_keepintvl, self_keepcnt 속성 설정에 따라 연결 대상에 대한 네트워크 접근에 문제가 없는지 확인한다. 전체 확인 과정에 실패하면, 해당 네트워크 연결을 강제로 종료시킨다.

(기본값: false)

self_keepidleint

접속 완료, DB 요청/응답 처리 등의 정상적인 네트워크 사용 이후, 다음 번의 정상 처리된 시간이 갱신되지 않을 때, 정상 상황으로 간주할 최대 시간을 지정한다. 지정된 시간이 지나면 네트워크 접근에 대한 확인 절차가 시작된다. self_keepalive 설정이 true인 경우에만 유효하다.

(단위: 초, 기본값: 60)

self_keepintvlint

매 번 확인할 때의 간격 및 한 번 확인할 때 최대 대기 시간을 지정한다. self_keepalive 설정이 true인 경우에만 유효하다.

(단위: 초, 기본값: 10)

self_keepcntint확인 절차를 총 몇 회까지 수행할 것인지를 지정한다. 지정된 횟수만큼 연속으로 실패하여야만 전체 확인과정이 실패한 것으로 처리된다. self_keepalive 설정이 true인 경우에만 유효하다. (기본값: 3)
failover_retry_countint

Failover 기능이 활성화되었을 때 연결 복원을 시도하는 최대 횟수를 지정한다. (기본값: 3)

Failover 기능에 대한 자세한 설명은 “제9장 Failover와 Load balancing”의 내용을 참고한다.

tbJDBC는 JDBC 타입을 지원할 뿐만 아니라 Interval 타입을 추가로 제공한다.

다음은 JDBC 타입과 tbJDBC 타입과의 대응 관계를 나타내는 표이다.

JDBC 타입(표준)Java 타입(표준)tbJDBC 타입
java.sql.Types.CHARjava.lang.Stringjava.lang.String
java.sql.Types.VARCHARjava.lang.Stringjava.lang.String
java.sql.Types.LONGVARCHARjava.lang.Stringjava.lang.String
java.sql.Types.NUMERICjava.math.BigDecimaljava.math.BigDecimal
java.sql.Types.DECIMALjava.math.BigDecimaljava.math.BigDecimal
java.sql.Types.BITbooleanboolean
java.sql.Types.TINYINTbytebyte
java.sql.Types.SMALLINTshortshort
java.sql.Types.INTEGERintint
java.sql.Types.BIGINTlonglong
java.sql.Types.REALfloatfloat
java.sql.Types.FLOATdoubledouble
java.sql.Types.DOUBLEdoubledouble
java.sql.Types.BINARYbyte[]byte[]
java.sql.Types.VARBINARYbyte[]byte[]
java.sql.Types.LONGVARBINARYbyte[]byte[]
java.sql.Types.DATEjava.sql.Datejava.sql.Date
java.sql.Types.TIMEjava.sql.Timejava.sql.Time
java.sql.Types.TIMESTAMPjava.sql.Timestampjava.sql.Timestamp
java.sql.Types.BLOBjava.sql.Blobcom.tmax.tibero.jdbc.TbBlob
java.sql.Types.CLOBjava.sql.Clobcom.tmax.tibero.jdbc.TbClob
java.sql.Types.NCLOBjava.sql.NClobcom.tmax.tibero.jdbc.TbNClob
java.sql.Types.NCHARjava.sql.NCHARjava.lang.String
java.sql.Types.NVARCHARjava.sql.NVARCHARjava.lang.String
java.sql.Types.SQLXMLjava.sql.SQLXMLcom.tmax.tibero.jdbc.TbSQLXML
com.tmax.tibero.jdbc.data.DataType.VARRAYjava.sql.Arraycom.tmax.tibero.jdbc.TbArray
com.tmax.tibero.jdbc.data.DataType.Structjava.sql.Structcom.tmax.tibero.jdbc.TbUpStruct
com.tmax.tibero.jdbc.data.DataType.CURSOR-com.tmax.tibero.jdbc.TbResultSet
com.tmax.tibero.jdbc.data.DataType.ITV_DTS-com.tmax.tibero.jdbc.TbIntervalDts
com.tmax.tibero.jdbc.data.DataType.ITV_YTM-com.tmax.tibero.jdbc.TbIntervalYtm
com.tmax.tibero.jdbc.data.DataType.RowId-com.tmax.tibero.jdbc.TbRowId
com.tmax.tibero.jdbc.data.DataType.TIMESTAMP_TZjava.sql.Timestampcom.tmax.tibero.jdbc.TbTimestampTZ
com.tmax.tibero.jdbc.data.DataType.TIMESTAMP_LTZjava.sql.Timestampjava.sql.Timestamp

참고

Tibero에서 TIME 데이터 타입을 지원하지만 DATE 데이터 타입을 사용하기를 권장한다.

TIME 컬럼에 대해서 PreparedStatement.setTime() 메소드로 지정할 수 없다. PreapredStatement.setTime()은 DATE 데이터 타입의 컬럼에 대해서 지원하고 있다. TIME 컬럼에 대한 값을 지정하기 위해서는 문자열을 TIME 값으로 변환하는 TO_TIME 함수를 통해서 입력할 수 있다.

tbJDBC에서는 특정 데이터 타입에 대해 다음과 같은 Stream 기능을 제공한다.

  • 컬럼에 대한 Stream 생성

    • CHAR, VARCHAR, RAW, NCHAR, NVARCHAR

    • LONG, LONG RAW

    • LOB

  • Stream 소멸

tbJDBC에서는 다음과 같이 4종류의 Stream 메소드를 제공한다.

메소드반환 값설명
getAsciiStreamJava.io.InputStreamASCII 형태로 변환된 데이터 Stream이다.
getBinaryStreamJava.io.InputStreambyte 형태로 변환된 데이터 Stream이다.
getUnicodeStreamJava.io.InputStreamUnicode 형태로 변환된 데이터 Stream이다. 이 메소드는 JDBC 4.0에서 폐기(deprecated)되었으므로 호환성을 고려하여 가급적 사용하지 않는 것이 좋다.
getCharacterStreamJava.io.Reader문자열 형태로 변환된 데이터 Reader이다.

각각의 메소드를 이용하면 해당 데이터 타입에서 허용하는 최대 크기까지 점진적으로 데이터를 읽을 수 있다. 메소드에서 반환되는 객체는 InputStream과 Reader이고, read() 메소드를 사용하면 데이터를 읽을 수 있다.

tbJDBC에서는 예외 상황을 처리하기 위해 java.sql.SQLException 클래스 객체를 정의할 수 있다. 예외 상황은 tbJDBC 내부에서 발생할 수도 있고, 데이터베이스 내부에서 발생할 수도 있다. 예외 상황의 내용은 에러 코드와 에러가 발생한 위치 등의 정보가 포함되어 있다.

예외 상황에 대한 정보를 얻기 위해 다음과 같은 메소드가 제공된다.

메소드설명
getMessage()에러가 발생한 원인이다.
getSQLState()SQL 상태 정보이다.
getErrorCode()에러 코드이다.
printStackTrace()에러가 발생한 스택의 트레이스 정보(Stack trace)이다.

다음은 위의 메소드를 사용하여 예외 상황을 처리하는 예이다.

try {
    stmt.execute("drop table not_exist_table");
}
catch (SQLException e) {
    System.out.println("ERROR[" + e.getErrorCode() + "]" + e.getMessage());
    e.printStackTrace();
}

실행하면 다음과 같은 정보가 화면에 출력된다.

ERROR[-7071] Schema object'NOT_EXIST_TABLE' was not found or is invalid.
java.sql.SQLException: Schema object 'NOT_EXIST_TABLE' was not found or is invalid.
   at com.tmax.tibero.jdbc.msg.common.TbMsgError.readErrorStackInfo(TbMsgError.java
:108)
   at com.tmax.tibero.jdbc.msg.TbMsgEreply.deserialize(TbMsgEreply.java:61)
   at com.tmax.tibero.jdbc.comm.TbStream.readMsgBody(TbStream.java:327)
   at com.tmax.tibero.jdbc.comm.TbCommType4.executeDirect(TbCommType4.java:460)
   at com.tmax.tibero.jdbc.TbStatement.executeInternal(TbStatement.java:1051)
   at com.tmax.tibero.jdbc.TbStatement.execute(TbStatement.java:560)
   at TestSimple.main(TestSimple.java:102)