내용 목차
본 장에서는 tbJDBC에서 LOB 데이터를 처리하는 방법을 설명한다.
JDBC 표준에서는 LOB 데이터를 처리하기 위해 두 가지 타입을 제공한다. BLOB(바이너리 데이터)와 CLOB(문자열 데이터)가 이에 해당한다. tbJDBC에서는 이 두 가지 타입을 효율적으로 처리하기 위해 지시자(locator)라는 개념을 사용한다.
일반적으로 LOB 데이터는 데이터베이스에 저장된 후에 지시자를 생성하여 데이터가 저장된 위치를 찾아갈 수 있도록 한다. 따라서 사용자는 이 지시자만을 사용하여 필요할 때마다 LOB 데이터를 읽고 쓸 수 있다. 이 때문에 시스템 성능을 향상시키는 데 도움을 줄 수 있다.
com.tmax.tibero.jdbc.TbBlob
com.tmax.tibero.jdbc.TbClob
JDBC 표준에서 제공하는 ResultSet 객체나 CallableStatement 객체의 메소드를 이용하여 LOB 지시자를 얻어올 수 있다.
ResultSet.getBlob() ResultSet.getClob() ResultSet.getObject()
다음은 ResultSet 객체를 이용하여 LOB 지시자를 얻어오는 예이다.
ResultSet rs = stmt.executeQuery("SELECT document, image FROM library"); while (rs.next()) { Clob document = rs.getClob(1); // 또는 Clob document = (Clob)rs.getObject(1); Blob image = rs.getBlob(2); // 또는 Blob image = (Blob)rs.getObject(1); }
CallableStatement.getBlob() CallableStatement.getClob() CallableStatement.getObject()
다음은 CallableStatement 객체를 이용하여 LOB 지시자를 얻어오는 예이다.
CallableStatement cstmt = conn.prepareCall("{call proc(?)}"); cstmt.registerOutParameter(1, Types.CLOB); cstmt.execute(); Clob document = cstmt.getClob(1); // 또는 Clob document = (Clob)cstmt.getObject(1);
JDBC 표준에서 제공하는 PreparedStatement 객체나 CallableStatement 객체의 메소드를 이용하여 LOB 지시자를 넘겨줄 수 있다.
PreparedStatement.setBlob() PreparedStatement.setClob() PreparedStatement.setObject()
다음은 PreparedStatement 객체를 이용하여 LOB 지시자를 넘겨주는 예이다.
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO library VALUES (?, ?)"); pstmt.setClob(1, document); // 또는 pstmt.setObject(1, document, Types.CLOB); pstmt.setBlob(2, image); // 또는 pstmt.setObject(1, image, Types.BLOB); pstmt.executeUpdate();
CallableStatement.setBlob() CallableStatement.setClob() CallableStatement.setObject()
다음은 CallableStatement 객체를 이용하여 LOB 지시자를 넘겨주는 예이다.
CallableStatement cstmt = conn.prepareCall("{call proc(?, ?)}"); cstmt.setClob(1, document); // 또는 cstmt.setObject(1, document, Types.CLOB); cstmt.setBlob(2, image); // 또는 cstmt.setObject(1, image, Types.BLOB); cstmt.execute();
LOB 지시자를 얻어오면 JDBC 표준에서 제공하는 API를 이용하여 데이터를 읽고 쓸 수 있다. LOB 데이터는 보통 Byte 배열이나 스트림 형태로 읽어올 수 있는데, 일반적인 스트림 형태와 달리 데이터베이스 서버 내부에 데이터가 있으므로 연결이 유지되는 한 언제든지 접근할 수 있다.
JDBC 표준에서는 LOB 데이터를 읽고 쓸 수 있도록 다음과 같은 API를 제공한다.
InputStream Clob.getAsciiStream()
Reader Clob.getCharacterStream()
String Clob.getSubString()
OutputStream Clob.setAsciiStream()
Writer Clob.setCharacterStream()
int Clob.setString()
InputStream Blob.getBinaryStream()
byte[] Blob.getBytes()
OutputStream Blob.setBinaryStream()
int Blob.setBytes()
다음은 LOB 데이터를 읽는 예이다.
// BLOB 데이터 InputStream is = image.getBinaryStream(); byte[] imageData = new byte[1000]; int readLength = is.read(imageData); // CLOB 데이터 Reader reader = document.getCharacterStream(); char[] docData = new char[1000]; int readLength = reader.read(docData, 0, docData.length);
다음은 LOB 데이터를 쓰는 예이다.
// BLOB 데이터 byte[] imageData = {32, 53, 78, 19, 2, 93}; OutputStream os = image.setBinaryStream(); os.write(imageData); // CLOB 데이터 char[] docData = {'J', 'D', 'B', 'C', '안', '내', '서'}; Writer writer = document.setCharacterStream(); writer.write(docData); writer.flush(); writer.close();
위의 예에서 OutputStream이나 Writer 객체는 데이터를 쓸 때마다 데이터베이스에 직접 전송되므로 별도의 UPDATE 문장을 실행할 필요가 없다. 하지만 LOB 자체는 트랜잭션 범위에 포함되므로 반드시 커밋을 수행해야 데이터베이스에 최종적으로 반영된다.
tbJDBC에서는 대용량 데이터를 LOB 형태로 저장하기 위해 임시 LOB을 제공한다. 단, 이 대용량 데이터는 테이블에 저장되지 않는다.
Connection.createBlob() return Blob
Connection.createClob() return Clob
Connection.createNClob() return NClob
Blob.free()
Clob.free()
NClob.free()
임시 LOB을 사용하여 저장한 데이터는 임시 테이블 스페이스에 저장된다. 이 영역에 저장된 데이터가 더는 필요하지 않게 되면, 사용자는 반드시 이것을 해제해야 한다. 그렇지 않으면 이 영역의 데이터는 계속 남아있게 된다.
임시 LOB는 LOB 컬럼의 데이터를 바인딩할 때 주로 사용한다. 예를 들면 다음과 같다.
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO library VALUES (?, ?)"); pstmt.setInt(1, 20090811); Clob doc = conn.createClob(); doc.setString(1, "JDBC Guide<br>writer:Rachael<br>proofreader:Patrick"); pstmt.setClob(2, doc); pstmt.executeUpdate(); doc.free(); pstmt.close();
위에서 나열한 메소드들은 JDBC 표준 API들로 일부 메소드는 Java 버전에 따라 사용할 수 없는 것들이 존재한다. 이를 위해 tbJDBC에서는 별도로 다음과 같은 구현 메소드들을 제공하고 있다. 이 메소드들을 이용할 경우 다른 JDBC와의 호환성은 떨어지지만 tbJDBC에 한하여 Java 버전에 관계 없이 사용할 수 있는 장점이 있다.
TbConnection.createTbBlob() return TbBlob
TbConnection.createTbClob() return TbClob
TbConnection.createTbNClob() return TbNClob
Tibero 4.0 SP1까지의 tbJDBC에서는 구현 메소드를 다음과 같은 형태로 제공하였으나, 호환성에 문제가 있어 폐기(deprecated)하고 위의 메소드들로 대체되었다.
static TbBlob.createTemporary(Connection conn) return
TbBlob static TbClob.createTemporary(Connection conn) return
TbClob static TbClob.createTemporaryNClob(Connection conn) return
TbClob TbBlob.freeTemporary() static TbBlob.freeTemporary(TbBlob blob) TbClob.freeTemporary() static TbClob.freeTemporary(TbClob clob) TbNClob.freeTemporary() static TbNClob.freeTemporary(TbNClob nclob)
tbJDBC에서는 LOB와 관련된 API로 BLOB, CLOB, NCLOB 메소드를 추가로 제공한다.
TbConnection 클래스에서는 다음과 같은 API를 추가로 제공한다.
API | 설명 |
---|---|
TbBlob createTbBlob() | 데이터베이스에 임시 BLOB을 생성한 후에 TbBlob 객체를 반환한다. |
TbClob createTbClob() | 데이터베이스에 임시 CLOB을 생성한 후에 TbClob 객체를 반환한다. |
TbNClob createTbNClob() | 데이터베이스에 임시 NCLOB을 생성한 후에 TbNClob 객체를 반환한다. |
TbBlob 클래스에서는 다음과 같은 API를 추가로 제공한다.
API | 설명 |
---|---|
TbBlob createEmptyBlob() | EMPTY_BLOB을 생성하여 반환한다. |
void close() | BLOB을 닫는다. |
OutputStream getBinaryOutputStream() | setBinaryStream(1L)과 동일하다. |
OutputStream getBinaryOutputStream(long) | setBinaryStream(long)과 동일하다. |
void open(int) | int 모드로 BLOB을 연다. |
TbClob 클래스에서는 다음과 같은 API를 추가로 제공한다.
API | 설명 |
---|---|
TbClob createEmptyClob() | EMPTY_CLOB을 생성하여 반환한다. |
void close() | CLOB을 닫는다. |
int getBufferSize() | 서버와 원활하게 통신할 수 있도록 32KB의 버퍼 크기를 반환한다. |
long getChars(long offset, char[] buffer) | offset 위치부터 CLOB 데이터를 읽어서 buffer에 저장한다. |
long getChars(long offset, char[] buffer, long numChars) | offset 위치부터 numChars만큼의 CLOB 데이터를 읽어서 buffer에 저장한다. |
long getChars(long offset, char[] buffer, long bufOffset, long numChars) | offset 위치부터 numChars만큼의 CLOB 데이터를 읽어서 buffer의 bufOffset 위치에 저장한다. |
void open(int) | int 모드로 CLOB을 연다. |
long putChars(long offset, char[] buffer) | buffer 데이터를 읽어서 offset 위치에 저장한다. |
long putChars(long offset, char[] buffer, long numChars) | buffer 데이터를 numChars만큼 읽어서 offset 위치에 저장한다. |
long putChars(long offset, char[] buffer, long bufOffset, long numChars) | buffer 데이터를 bufOffset 위치부터 numChars만큼 읽어서 offset 위치에 저장한다. |
TbNClob 클래스에서는 다음과 같은 API를 추가로 제공한다.
API | 설명 |
---|---|
TbNClob createEmptyNClob() | EMPTY_NCLOB을 생성하여 반환한다. |
void close() | NCLOB을 닫는다. |
int getBufferSize() | 서버와 원활하게 통신할 수 있도록 32KB의 버퍼 크기를 반환한다. |
long getChars(long offset, char[] buffer) | offset 위치부터 NCLOB 데이터를 읽어서 buffer에 저장한다. |
long getChars(long offset, char[] buffer, long numChars) | offset 위치부터 numChars만큼의 NCLOB 데이터를 읽어서 buffer에 저장한다. |
long getChars(long offset, char[] buffer, long bufOffset, long numChars) | offset 위치부터 numChars만큼의 NCLOB 데이터를 읽어서 buffer의 bufOffset 위치에 저장한다. |
void open(int) | int 모드로 NCLOB을 연다. |
long putChars(long offset, char[] buffer) | buffer 데이터를 읽어서 offset 위치에 저장한다. |
long putChars(long offset, char[] buffer, long numChars) | buffer 데이터를 numChars만큼 읽어서 offset 위치에 저장한다. |
long putChars(long offset, char[] buffer, long bufOffset, long numChars) | buffer 데이터를 bufOffset 위치부터 numChars만큼 읽어서 offset 위치에 저장한다. |