Akashic Records

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

오래된글/Java

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

Andrew's Akashic Records 2018. 4. 7. 22:58
728x90

만약 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()를 호출하여 데이터를 추출한다.


728x90

'오래된글 > Java' 카테고리의 다른 글

EJB CMP의 단점  (0) 2018.04.07
Scrolling Result Sets  (0) 2018.04.07
JDBC driver types  (0) 2018.04.07
What is the way of Direct Memory Access in Java?  (0) 2018.04.07
Easy java Persistence  (0) 2018.04.07
Comments