Dashboard > RIFE > ... > Database > Database independence
RIFE Log In | Sign Up   View a printable version of the current page.
Database independence


Added by Steven Grimm, last edited by Steven Grimm on Jul 17, 2006  (view change) show comment
Labels: 
(None)

In the user's manual's Friends database example, the elements all used a hard coded query manager, FriendManager, by explicitly creating it:

public void processElement()
{
  Template template = getHtmlTemplate("display");

  FriendManager manager = new FriendManager();
  ...
}

This works fine for simple cases, such as when you only use a small subset of database features that work exactly the same on a wide range of servers. It also would be fine when only one database server needs to be supported. Unfortunately, both those cases are quite rare.

The only way to solve this is by writing a separate database driver for each server. A good pattern that helps doing this cleanly and efficiently is to split the code in two parts: one that is common to all databases and one that isn't. The recommended way to do this with RIFE is to specify an interface for the manager, with methods for all database operations, such as install, remove, add, display like in our example.

Then we write an abstract subclass of DBQueryManager, with methods that matches the interface, but prefixed with an underscore, like _install, _remove, _add, _display and so on. In those methods, we put the parts that are independent of which database is used, for example checking that parameters are valid, executing statements and processing the results.

After doing this split, writing a driver for a specific database becomes a rather simple task. A driver is just a subclass of the abstract manager class mentioned above, and handles database dependent code like building queries and handling exceptions. This is done in the implementation of the interface, that is the methods install, remove and add, etc. A simple example might look like the following:

Datasource dependent implementation
public void add(Friend friend)
throws TextManagerException
{
  // here we can perform database specific tasks

  ...

  // then we let the manager superclass perform the database
  // independent task

  try
  {
    _add(sAdd, friend);
  }
  catch (FriendManagerException e)
  {
    // ... handle the exception, which often is database dependent
  }
 }

Finally, we'll take a look at the corresponding method in the shared part. The actual implementation is not important here, but notice the general structure, with no database dependent code:

Datasource independent implementation
protected void _add(Select addQuery, Friend friend)
throws TextManagerException
{
  try
  {
    DbPreparedStatement ps_add = getPreparedStatement(addQuery);
    try
    {
      ps_add.setBean(friend);
      ps_add.executeQuery();
    }
    finally
    {
      ps_add.close();
    }
  }
  catch (DatabaseException e)
  {
    throw new AddErrorException(friend, e);
  }
}



Are you enjoying Confluence? Please consider purchasing it today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.2.1a Build:#515 May 19, 2006) - Bug/feature request - Contact Administrators