버전이 8.2로 넘어오면서 LargeObject id가 int 에서 long으로 바뀌었군요.

8.0버전으로 뻘짓하다가 다시 수정합니다. ㅜㅜ

참조http://jdbc.postgresql.org/d0cumentation/82/binary-data.html

//본문과 코드에 오타가 있을 수 있습니다.

PostgreSQL은 두 가지 방식으로 바이너리 데이터를 저장할 수 있도록 해줍니다.

'bytea' 데이터 타입이나 또는 'Large Object'로써 바이너리 데이터는

분리된 테이블에 특별한 형식으로 저장하고, 연결된 테이블에서 참조하도록 하거나 하는

두 가지 입니다.

bytea 데이터 타입은 1GB까지 바이너리 데이터를 저장할 수 있지만, 큰 크기의

바이너리 데이터를 처리하기 위해서는 많은 메모리를 소모하게 됩니다.

Large Object 를 이용한 방법은 더 큰 데이터를 저장하기에 알맞지만,

Large Object를 지울 때는 참조 테이블의 Row를 지우고, 또한

Large Object를 또 지워주는 작업을 해주어야 합니다.

Large Object는 또한 데이터 베이스에 연결된 모든 사용자가 보거나

수정할 수 있기 때문에 보안상의 문제가 있을 수 있습니다.

또 중요한 점은 Large Object는 SQL tracnsaction block 안에서 접근해야 합니다.

transaction block 은 setAutoCommint(false)로 할 수 있습니다.

----------------------------------------------------------------------------------------

bytea 데이터 타입을 활용하는 방법

----------------------------------------------------------------------------------------

우선 테이블을 만들어야 하겠습니다.

CREATE TABLE image( imgname text, img bytea);

위와 같은 SQL 문을 사용하여 테이블을 만들어 줍니다.

다음은 자바 코드입니다.

File file = new File("myimage.gif");

FileInputStream fis = new FileInputStream(file);

PreparedStatement ps = conn.prepareStatement("INSERT INTO images VALUES (?, ?)");

ps.setString(1, file.getName());

ps.setBinaryStream(2, fis, (int) file.length());

ps.executeUpdate();

ps.close();

fis.close();

위와 같은 식으로 Row를 추가하게 됩니다.

다음은 img데이터를 가져오는 코드입니다.

PreparedStatement ps = conn.prepareStatement("SELECT img FROM WHERE imgname = ?");

ps.setString(1, "myimage.gif");

ResultSet rs = ps.executeQuery();

while (rs.next()) {

byte[] imgBytes = rs.getBytes(1);

// 데이터를 사용하는 코드가 여기에 들어갑니다.

}

rs.close();

ps.close();

데이터를 받을 때 byte[]를 사용했는데 Inputstream을 사용해도 됩니다.

----------------------------------------------------------------------------------------

Large object를 사용하는 방법

----------------------------------------------------------------------------------------

우선 테이블을 만듭니다.

CREATE TABLE imageslo ( imgname text, imgoid oid );

다음은 역시 데이터를 업데이트 하는자바 코드입니다.

//모든 Large Object API는 transaction block안에서 호출되어야 합니다.

conn.setAutoCommit(false);

//Large Object Manage를 가져옵니다.

LargeObjectManager lobj = ( (org.postgresql.PGConnection)conn).getLargeObjectAPI();

//새로은 Large Object 생성합니다.

longoid = lobj.createLO(LargeObjectManager.READ | LargeObjectManager.WRITE );

// 쓰기 위해서 Large object를 엽니다.

LargeObject obj = lobj.open(oid, LargeObjectManger.WRITE);

// 파일을 엽니다.

File file = new File("myimage.gif");

FileInputStream fis = new FileInputStream(file);

// 파일의 데이터를 Large Object에 복사합니다.

byte buf[] = new byte[2048];

int s, tl = 0;

while ( (s = fis.read(buf, 0, 2048) ) > 0 ) {

obj.write(buf, 0, s);

tl += s;

}

// Large object를 닫습니다.

obj.close();

// imageslo테이블에 새로운 열을 추가합니다.

PreparedStatement ps = conn.prepareStatement("INSERT INTO imageslo VALUES (?, ?)");

ps.setString(1, file.getName());

ps.setInt(2, oid);

ps.executeUpdate();

ps.close();

fis.close();

// 마지막으로 transaction을 실행(commit)합니다.

conn.commit();

다음은 Large Object로부터 파일을 가져오는 과정입니다.

// 역시, transaction block안에서 시작합니다.

conn.setAutoCommit(false);

// 작업을 하기 위해 Large Object Manager를 얻어 옵니다.

LargeObejectManage lobj = ( (org.postgresql.PGConnection)conn).getLargeObjectAPI();

PreparedStatement ps = conn.prepareStatement("SELECT imgoid FROM imageslo WHERE imgname = ?");

ps.setString( 1, "myimage.gif");

ResultSet rs = ps.executeQuery();

while (rs.next()) {

// 읽기 위한 Large object를 엽니다.

int oid = rs.getInt(1);

LargeObject obj = lobj.open(oid, LargeObjectManager.READ);

// 데이터를 읽어 옵니다.

byte buf[] = new byte[obj.size()];

obj.read(buf, 0, obj.size());

// 데이터를 처리하는 코드를 이 곳에 넣습니다.

// object를 닫습니다.

obj.close();

}

rs.close();

ps.close();

// 마지막으로 transaction을 실행합니다.

conn.commit();

결론....

편한 코딩과 보안을 위해서는 bytea라는 데이터 타입을 사용하고,

1GB이상의 크기를 가진 데이터를 처리하기 위해서는

Large Object를 사용해야 합니다. Large Object 또한 pg_largeobject 라는 기본 테이블에 bytea 타입으로 저장되므로 지우고 나서 VACUUM이 실행되어야 물리적인디스크 공간을 확보할 수 있습니다.

현재 프로젝트에서 멀티미디어 데이터의 크기가 어느 정도인지 알 수 없으므로

일단 Large Object로 처리해야 하겠군요.

, .