2011년 6월 9일 목요일

객체 저장 : Storing Classes, Images and Other Large Objects

만약 long raw, longvarbinary, 혹은 다른 유사한 타입이 데이터베이스에 제공된다면, 많은 데이터베이스는 바이너리 데이터를 열의 일부로 저장할 수 있다. 이들 필드는 2기가 바이트까지 수용할 수 있다. 이것은 여러분이 데이터를 바이너리 스트림이나 바이트 배열로 변환할 수 있다면, string이나 double과 같은 방법으로 데이터 베이스에 저장되고 추출될 수 있음을 의미한다.
이 기술은 이미지나 Java 객체를 저장하고 추출하는데 사용될 수 있다.
Storing and retrieving an image: 직렬화되었거나, 바이트 배열로 변환된 객체를 저장하는 것은 매우 쉽다. 불행하게도 java.awt.ImageSerializable 되지 않는다. 그러나, 다음 코드에서와 같이 이미지 데이터를 파일로 저장할 수 있고, 파일에 있는 정보를 데이터베이스 바이너리 필드에 바이트로 저장할 수 있다.

int itemnumber=400456;

 File file = new File(itemnumber+".jpg");
 FileInputStream fis = new FileInputStream(file);
 PreparedStatement pstmt = con.prepareStatement(
       "update auctionitems
       set theimage=? where id= ?");
 pstmt.setBinaryStream(1, fis, (int)file.length()):
 pstmt.setInt(2, itemnumber);
 pstmt.executeUpdate();
 pstmt.close();
 fis.close();

이미지를 추출하고 createImage 로 전달될 수 있는 바이트 배열로 생성하기 위해서는 아래와 같이 하라:
int itemnumber=400456;
 byte[] imageBytes;

 PreparedStatement pstmt = con.prepareStatement(
   "select theimage from auctionitems where id= ?");
 pstmt.setInt(1, itemnumber);
 ResultSet rs=pstmt.executeQuery();
 if(rs.next()) {
   imageBytes = rs.getBytes(1);
 }
 pstmt.close();
 rs.close();

 Image auctionimage =
       Toolkit.getDefaultToolkit().createImage(imageBytes);
Storing and retrieving an object: 클래스는 전의 예에서 이미지와 같은 방법으로 바이너리 데이터베이스 필드로 직렬화될 수 있다. RegistrationImpl 클래스는 클래스 선언에 implements Serializable를 추가함으로써 기본적인 직렬화를 지원하도록 수정될 수 있다.
다음, ByteArrayInputStream 이 JDBC 바이너리 스트림으로서 전달되도록 생성된다. ByteArrayInputStream을 생성하기 위해, RegistrationImpl 은 우선 RegistrationImpl.writeObject을 호출하는 ByteArrayInputStream 에 기반한 ObjectOutputStream 에 파이프(pipe)화된다(연결통로를 만듦). ByteArrayInputStream 은 바이트 배열로 변환되고, 그것은 ByteArrayInputStream 을 생성하는데 주로 사용된다. RegistrationServer.java is의 create 메소드는 아래와 같이 바뀐다:

public registration.RegistrationPK create(
       String theuser,
       String password,
       String emailaddress,
       String creditcard)
       throws registration.CreateException{

    double balance=0;
    Connection con = null;
    PreparedStatement ps = null;;

    try {
       con=getConnection();
       RegistrationImpl reg= new RegistrationImpl();
       reg.theuser = theuser;
       reg.password = password;
       reg.emailaddress = emailaddress;
       reg.creditcard = creditcard;
       reg.balance = balance;

       ByteArrayOutputStream regStore =
               new ByteArrayOutputStream();
       ObjectOutputStream regObjectStream =
               new ObjectOutputStream(regStore);
          regObjectStream.writeObject(reg);

       byte[] regBytes=regStore.toByteArray();
       regObjectStream.close();
       regStore.close();
       ByteArrayInputStream regArrayStream =
               new ByteArrayInputStream(regBytes);
       ps=con.prepareStatement(
               "insert into registration (
               theuser, theclass) values (?, ?)");
       ps.setString(1, theuser);
       ps.setBinaryStream(2, regArrayStream,
            regBytes.length);

       if (ps.executeUpdate() != 1) {
           throw new CreateException ();
       }
       RegistrationPK primaryKey =
                        new RegistrationPKImpl();
       primaryKey.theuser(theuser);
       return primaryKey;
    } catch (IOException ioe) {
      throw new CreateException ();
    } catch (CreateException ce) {
      throw ce;
    } catch (SQLException sqe) {
      System.out.println("sqe="+sqe);
      throw new CreateException ();
    } finally {
      try {
         ps.close();
        con.close();
      } catch (Exception ignore) {
      }
    }
 }
데이터베이스로부터 바이트를 추출하고, ObjectInputStream으로부터 읽혀질 수 있는 그 바이트들로부터 ByteArrayInputStream 생성하고, 다시 인스턴스를 생성하기 위해 readObject를 호출함으로써 객체는 얻어지고 재생성된다.

다음 예는 데이터베이스에서 registration 인스턴스를 추출하는 egistrationServer.refresh 메소드가 필요한 것을 보여준다.

private Registration refresh(RegistrationPK pk)
               throws FinderException {

     if (pk == null) {
         throw new FinderException ();
     }
     Connection con = null;
     PreparedStatement ps = null;
     try {
        con=getConnection();
        ps=con.prepareStatement("
               select theclass from
               registration where theuser = ?");
        ps.setString(1, pk.theuser());
        ps.executeQuery();
        ResultSet rs = ps.getResultSet();
        if(rs.next()){
           byte[] regBytes = rs.getBytes(1);
           ByteArrayInputStream regArrayStream =
               new ByteArrayInputStream(regBytes);
           ObjectInputStream regObjectStream =
               new ObjectInputStream(
                     regArrayStream);
           RegistrationImpl reg=
               (RegistrationImpl)
                      regObjectStream.readObject();
           return reg;
        }
        else {
            throw new FinderException ();
        }
    } catch (Exception sqe) {
        System.out.println("exception "+sqe);
        throw new FinderException ();
    }
    finally {
       try {
          rs.close();
          ps.close();
          con.close();
       }
       catch (Exception ignore) {}
    }
 }

BLOBs and CLOBs: 만약 데이터의 사이즈가 가변이라면, 다른 데이터를 가진 테이블에 큰 필드를 저장하는 것은 반드시 최적의 장소는 아니다. 크고 가변인 크기의 객체를 다루는 한 방법은 Large Objects(LOBs)를 사용하는 것이다. LOB는 레코드에서 실제 데이터베이스 필드를 포인트하는 로케이터(Locator- 실제로는 포인터인)를 사용한다.
LOB는 2가지 타입 : Binary Large Object(BLOB)와 Character Large Object(CLOB)이다. 여러분이 BLOB 혹은 CLOB를 액세스 할 때, 데이터는 클라이언트에 복사되지 않는다. 결과(resultset)으로 실제 데이터를 추출하려면, BLOB blob=getBlob(1) 혹은 CLOB clob=getClob(1)를 호출하여 포인터를 얻어야 하고, blob.getBinaryStream() 혹은 clob.getBinaryStream()를 호출하여 데이터를 추출한다.

댓글 없음:

댓글 쓰기

블록체인 개요 및 오픈소스 동향

블록체인(block chain) 블록체인은 공공 거래장부이며 가상 화폐로 거래할때 발생할때 발생할 수 있는 해킹을 막는 기술. 분산 데이터베이스의 한 형태로, 지속적으로 성장하는 데이터 기록 리스트로서 분산 노드의 운영자에 의한 임의 조작이 불가...