2011-08-24 71 views
1

我想弄清楚使用hibernate在數據庫中實現大文件(〜600 MB)存儲庫的對象設計。 請建議正確的方法/設計?Java大文件被保存在數據庫中 - 對象設計

class ModelClass{ 

String name; //meta data 
... 

Option 1. 
    byte[] file; // dont want to load the content of the entire file 
          // in memory by using this but hibernate recognizes 
          // this datatype 
Option 2. 
    InputStream inputStream; 
    OutputStream outputStream; 
    // I can have the methods to provide the input or output stream 
       // but i dont think its a clean approach. I am not sure how 
       // I will be able to work with hibernate with streams 
Option 3. 
    File fileHandle; 
} 

任何其他選項??

我想調用hibernateTemplate的save(Object)方法將對象保存到數據庫中。不知道我是否應該只有班級中的元數據,並單獨處理文件保存和檢索。

在此先感謝。

另一個可行的解決方案是使用「工作」接口。目的是避免將文件內容加載到內存中。

session.doWork(new Work(){ 
    @Override 
    public void execute(Connection conn) { 
     //direct sql queries go here 
    } 

}); 
+0

將這樣一個大文件存儲在數據庫中的原因是什麼? –

+1

將文件保存在磁盤上並在數據庫中存儲路徑不是一個好的解決方案嗎? –

+0

不幸的是,它需要將大型zip文件存儲在數據庫中。 – nkare

回答

1

我已經寫了一個SerializableFile類來保存文件中的數據。讀取對象時,會創建一個臨時文件。 這就是:

public class SerializableFile implements Serializable { 
    private static final File TEMP_DIR = getTempDir(); 

    private transient boolean temporary; 
    private transient String name; 
    private transient File file; 

    public SerializableFile() { 
    } 

    public SerializableFile(File file) { 
     this.file = file; 
     this.name = file.getName(); 
     this.temporary = false; 
    } 

    @Override 
    protected void finalize() throws Throwable { 
     dispose(); 
     super.finalize(); 
    } 

    public void dispose() { 
     if (temporary && file != null) { 
      file.delete(); 
      file = null; 
     } 
    } 

    public File keep(String name) throws IOException { 
     if (temporary) { 
      temporary = false; 
     } else { 
      File newFile = new File(TEMP_DIR, name); 
      keepAs(newFile); 
      file = newFile; 
     } 
     return file; 
    } 

    public void keepAs(File outFile) throws IOException { 
     if ((temporary || file.equals(outFile)) && file.renameTo(outFile)) { 
      temporary = false; 
      file = outFile; 
     } else { 
      InputStream in = new FileInputStream(file); 
      try { 
       OutputStream out = new FileOutputStream(outFile); 
       try { 
        byte buf[] = new byte[4096]; 
        for (int n = in.read(buf); n > 0; n = in.read(buf)) { 
         out.write(buf, 0, n); 
        } 
       } finally { 
        out.close(); 
       } 
      } finally { 
       in.close(); 
      } 
      outFile.setLastModified(file.lastModified()); 
     } 
    } 

    public String getName() { 
     return name; 
    } 

    public File getFile() { 
     return file; 
    } 

    public long lastModified() { 
     return file.lastModified(); 
    } 

    private void writeObject(ObjectOutputStream out) throws IOException { 
     int size = (int)file.length(); 
     long date = file.lastModified(); 
     out.writeUTF(name); 
     out.writeInt(size); 
     out.writeLong(date); 
     InputStream in = new FileInputStream(file); 
     try { 
      byte buf[] = new byte[4096]; 
      while (size > 0) { 
       int n = in.read(buf); 
       if (n <= 0 || n > size) { 
        throw new IOException("Unexpected file size"); 
       } 
       out.write(buf, 0, n); 
       size -= n; 
      } 
     } finally { 
      in.close(); 
     } 
    } 

    private void readObject(ObjectInputStream in) throws IOException { 
     name = in.readUTF(); 
     int size = in.readInt(); 
     long date = in.readLong(); 
     file = File.createTempFile("tmp", ".tmp", TEMP_DIR); 
     OutputStream out = new FileOutputStream(file); 
     try { 
      byte buf[] = new byte[4096]; 
      while (size > 0) { 
       int n = in.read(buf, 0, size <= buf.length ? size : buf.length); 
       if (n <= 0 || n > size) { 
        throw new IOException("Unexpected file size"); 
       } 
       out.write(buf, 0, n); 
       size -= n; 
      } 
     } finally { 
      out.close(); 
     } 
     file.setLastModified(date); 
     temporary = true; 
    } 

    private static File getTempDir() { 
     File dir; 
     String temp = System.getProperty("com.lagalerie.live.temp-dir"); 
     if (temp != null) { 
      dir = new File(temp); 
     } else { 
      String home = System.getProperty("user.home"); 
      dir = new File(home, "temp"); 
     } 
     if (!dir.isDirectory() && !dir.mkdirs()) { 
      throw new RuntimeException("Could not create temp dir " + dir); 
     } 
     return dir; 
    } 
} 
+0

謝謝Maurice。但是你提供的示例代碼讀/寫磁盤。我正在尋找使用hibernate讀取/寫入數據庫。 – nkare

+0

在你的ModelClass中聲明一個SerializableFile類型的字段,將它映射到你的數據庫的blob字段,它將會是。 –

0

打開JPA支持與some databases一個@Persistent註釋:

  • MySQL的
  • 甲骨文
  • PostgreSQL的
  • SQL服務器
  • DB2
+0

我不認爲我會被允許引入新的框架,但我傾向於使用SQL數據類型「Blob」並公開兩個方法,它們將設置/獲取contentStream並使用hibernate的createBlob方法。需要確定createBlob是否將數據存儲在內存中。 – nkare

0

即使你還在使用RDBMS作爲數據存儲,你應該考慮將這個二進制數據到一個文件系統,並保存路徑的目錄/位置到數據庫中,而不是將其作爲BLOBCLOB存儲到數據庫中。

+0

服務器安裝在羣集環境中,沒有可用的公用文件共享。我們需要將文件存儲在數據庫中。 – nkare

+0

一個不幸的需求和「解決方案」,如果使用存儲在rdbms中的clob/blob進行交付。 –