Thursday, May 18, 2006

Say Goodbye to your Relational Database

db40 Has Entered the Building

I have been using db4o a LOT lately, and I don't expect I shall return. I can say without question that it has increased my productivity by at least... 1 million times. Well probably not that much, but a heck of a lot. It definitely takes a bit of getting use to if you come from a relational database world, but consider never having to map your objects to a relational database. And how about never having to make the database at all! You just worry about your object model and db4o will take care of the persistence (long term storage).

Check out these examples to see just how easy it is.

Starting the Database Server

// openServer() takes the filename where you want your database stored and a port
ObjectServer server = Db4o.openServer("somefilename.yap", 1234);
// Now you can give access to particular logins
server.grantAccess("username","password");
There are other ways of doing this: you can run it in non-server mode, but I don't recommend that since you'll probably just end up changing it down the road if your application is multi-threaded (and what application isn't these days?); you can also use an embedded server by using port zero [ObjectServer server = Db4o.openServer("somefilename.yap", 0);] and getting connections from the ObjectServer directly [ObjectContainer db = server.openClient();] which isn't too bad because it'll be faster, but it can't be networked.

When your program is ready to shutdown, you'll want to call server.close() to shut it down.

Getting a Connection

ObjectContainer db = Db4o.openClient("localhost",PORT,USER,PASSWORD);
try{
// with the client, we can do all the fun stuff in the examples below
// ALL EXAMPLES ARE ASSUMED TO BE PLUGGED IN HERE
} finally {
db.close();
}

Saving and Updating an Object

Doesn't get much easier than this.
db.set(myObject);

Query

This is equivalent to your SQL Select. For this example, lets say we saved a couple of objects that looked like this:
Contact contact = new Contact();
contact.setName("Travis");
db.set(contact);
contact = new Contact();
contact.setName("Jimbo");
db.set(contact);
Now to query for the contact named Travis, you do this:
Query q = db.query();
q.constrain(Contact.class);
q.descend("name").constrain("Travis");
ObjectSet result = q.execute();
while (result.hasNext()) {
Contact c = (Contact) result.next();
System.out.println("Contact: " + c.getName());
}

The example above is a SODA query which as you can see, uses strings and can be built dynamically. db4o does have another method of querying called Native Queries. db4objects recommends Native Queries and it's for good reason. Native queries don't reference fields by strings, they're compile time checked, are object oriented and, most importantly, they are refactorable.


List <Contact> contacts = db.query(new Predicate<Contact>() {
public boolean match(Contact contact) {
return contact.getName().equals("Travis");

}

});

for (Contact contact: contacts) {

System.out.println("Contact: " + c.getName());

}

Deleting an Object

db.delete(myObject);

Gotchas

Now not everything is greener on the other side, there are still many little gotchas that may bite you, for instance:
  • No ID support like Hibernate / EJB so you can't let db4o rebind objects based on an id field in your objects
    • This is extremely apparent in a web based application where you have to be sure to reload your objects in every request, so they can be in your new db4o session (assuming session per request pattern). I have figured out ways to work around this though to make it automated and I'll try to share these with you in a later post.
  • Weak management GUI
    • If you're used to working with nice tools like the tools provided by major database vendors, the db4o Object Manager doesn't really compare. But hopefully with time and with more adopters, the Object Manager will get better and we'll see third party tools.
  • No joins
    • This isn't bad if your object model is not complex and you can have all your objects connected to each other in your object graph, but you have to be careful when your data set gets large and your object model is a complex graph with bidirectional relationships because you may end up loading your entire database! Or at least a good chunk of data that you may not always need. And this is a *huge* performance killer.
    • Now the obvious answer would be to break apart your object model which is easy to do in a relational database because you have id's and foreign keys. In db4o, if you break apart your model, there is no built in way to reference your disconnected objects.
    • It is possible to workaround this though, by using keys and ID's as fields in your objects and querying for the related objects when you need them.

Conclusion

In any case, Carl Rosenberger and the db4objects folks have done a great job with this open source object database and they are definitely the leaders in the space. The simplicity, performance, and productivity gains outweight and disadvantages by a long shot. I urge you to try it.

Also, I plan on sharing more of my experiences with db4o in the near future, along with code such as how to easily use it in a web application, how to partition, and how to scale.




Tags: | |