Db4o Blob Implementation

Built-in db4o Blob type helps you to get rid of the problems of byte[] array, though it has its own drawbacks. Pros and Cons for the points, mentioned above:

  1. every Blob gets it's own file
  2. + main database file stays a lot smaller

    + backups are possible over individual files

    + the BLOBs are accessible without db4o

    - multiple files need to be managed

  3. C/S communication runs asynchronous in separate thread
  4. + asynchronous storage allows the main application thread to continue its work, while blobs are being stored

  5. special code is necessary to store and load
  6. - it is more difficult to move objects between db4o database files

  7. no concerns about activation depth
  8. + big objects won't be loaded into memory as part of the activation process

Let's look, how it works.

First, BLOB storage should be defined:

Java: Db4o.configure().setBlobPath(storageFolder);

[/filter]

where storageFolder is a String value representing local or server path to store BLOBs. If that value is not defined, db4o will use the default folder "blobs" in user directory.

We will use a modified Car class, which holds reference to the car photo:

Car.java
01/* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com */ 02package com.db4odoc.blobs; 03 04public class Car { 05 private String model; 06 private CarImage img; 07 08 09 public Car(String model) { 10 this.model=model; 11 img=new CarImage(); 12 img.setFile(model+".jpg"); 13 } 14 15 public CarImage getImage() { 16 return img; 17 } 18 19 public String toString() { 20 return model +"(" + img.getFile() + ")" ; 21 } 22}

[filter=vb]VB: IBlob.ReadFrom( File )

As reading is done in a dedicated thread, you can use Blob#getStatus() in a loop to create a progress window.

The same applies to the write operation, which copies BLOB, stored with db4o, to the specified filesystem location.

Let's store some cars together with their images in our database:

BlobExample.java: storeCars
01private static void storeCars() { 02 new File(DB4O_FILE_NAME).delete(); 03 ObjectContainer container=Db4o.openFile(DB4O_FILE_NAME); 04 try { 05 Car car1=new Car("Ferrari"); 06 container.set(car1); 07 storeImage(car1); 08 Car car2=new Car("BMW"); 09 container.set(car2); 10 storeImage(car2); 11 } finally { 12 container.close(); 13 } 14 }

CarImage is stored in the database just like normal object, no BLOB data is transferred before explicit call (Blob#readFrom in CarImage#readFile method), which copies the images to the storageFolder.

Please, note, that CarImage reference should be set to the database before uploading actual data. To get the images back to the filesystem we can run a usual query:

BlobExample.java: retrieveCars
01private static void retrieveCars() { 02 ObjectContainer container=Db4o.openFile(DB4O_FILE_NAME); 03 try { 04 Query query = container.query(); 05 query.constrain(Car.class); 06 ObjectSet result = query.execute(); 07 getImages(result); 08 } finally { 09 container.close(); 10 } 11 }

and get BLOB data using retrieved Car references:

BlobExample.java: getImages
01private static void getImages(ObjectSet result){ 02 while(result.hasNext()) { 03 Car car = (Car)(result.next()); 04 System.out.println(car); 05 CarImage img = car.getImage(); 06 try { 07 img.writeFile(); 08 } catch (java.io.IOException ex){ 09 System.out.print(ex.getMessage()); 10 } 11 } 12 }

Retrieved images are placed in CarImage.outFolder ("blobs\out").

So query interface operates on references - no BLOB data is loaded into memory until explicit call (Blob#writeTo). This also means, that activationDepth does not affect Blob objects and best querying performance is achieved without additional coding.