글
버전이 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로 처리해야 하겠군요.
'PostgreSQL' 카테고리의 다른 글
Data Type - 데이터 타입 (3) | 2009.12.29 |
---|---|
postgresql, 우편번호를 DB에 넣어보자 (0) | 2009.12.29 |
Oracle PL/SQL에서 PG/pgSQL로 변환 (0) | 2009.12.24 |
PL/pgSQL 는 Postgres 데이터베이스를 위한 적재가능한 절차형 언어. (0) | 2009.12.24 |
PostgreSQL 8.3의 내장 자료형들 (0) | 2009.08.13 |
RECENT COMMENT