Java Persistence
Java Persistence Introduction
The DAO Design Pattern
DAO Design Problems
DAO Manager
Advanced Connection and Transaction Demarcation and Propagation
 


The DAO Manager

Connect with me:  
  Jenkov.com - News

The DAO Manager is a solution to the problems not solved in the text DAO Design Problems: That the demarcation of the connection and transaction scopes still leak out from the DAO layer into the business layer / domain layer / service layer (or whatever layer you have ontop of your DAO layer). Additionally you have a lot of ugly exception handling in the domain logic, which you have to repeat everywhere the domain logic uses DAO's.

Here is a list of the topics covered in this text:

  1. The DaoManager
  2. DaoManager Connection Scoping
  3. DaoManager Transaction Scoping
  4. Single Point of Access for DAO's
  5. Hiding the Scope Boundary Code
  6. Lazy Opening of Connection

The DaoManager

To solve the problems mentioned earlier, you can move some of the code to a DaoManager class. Instead of instantiating each DAO separately I will now only instantiate the DaoManager.

From the DaoManager I will have access to every DAO in the DAO layer. Each DAO will be created lazily of course, to avoid instantiating more DAO's than necessary. The DaoManager will be created with a connection as instance member. When a DAO is created lazily this connection is passed to it. That way all DAO's accessed from that particulary DaoManager uses the same connection. This solves the problem of marking the beginning of a connection scope. The instantiation of the DaoManager marks this now.

Here is a sketch of a DaoManager:

public class DaoManager{
  protected Connection connection = null;
  protected PersonDao  personDao  = null;

  public DaoManager(Connection connection){
    this.connection = connection;
  }

  public PersonDao getPersonDao(){
    if(this.personDao == null){
      this.personDao = new PersonDao(this.connection);
    }
    return this.personDao;
  }

}

In this sketch only a single DAO is obtainable, PersonDao, but you could easily add more DAO's along the same model.

Notice that the getPersonDao() method isn't synchronized even though it returns a kind of singleton. The DaoManager is not intended for sharing between threads, so no synchronization is inserted. Doing so would be quite easy though.


DAO Manager Connection Scoping

Using the DaoManager as sketched above would look like this:

DaoManager daoManager = daoFactory.createDaoManager();

Person person = daoManager.getPersonDao().readPerson(666);

Notice how the connection is not closed in this example. Rather than implementing a close() method in the DaoManager class, a template method will be added called executeAndClose(). Here is a sketch of that method without exception handling:

public class DaoManager{
  ...

  public Object executeAndClose(DaoCommand command){
    try{
      return command.execute(this);
    } finally {
      this.connection.close();
    }
  }

}
public interface DaoCommand {
  public Object execute(DaoManager daoManager);
}

Using that method would look like this:

DaoManager daoManager = daoFactory.createDaoManager();

Person person = (Person)
    daoManager.executeAndClose(new DaoCommand(){

      public Object execute(DaoManager manager){
        return manager.getPersonDao().readPerson(666);
      }

    });

The executeAndClose() method is called with a DaoCommand instance. This instance then has it's execute() method invoked with the DaoManager itself as parameter. When the execute() returns the executeAndClose() closes the connection. Now the scope of the connection is marked by the scope of the method call executeAndClose(). Any exception handling related to the connection.close() call can be hidden away inside the executeAndClose() method, and reused throughout the application.

This may look like a lot of code just to read a Person but most of the code can be generated by your IDE's code completion. And, once you get used to reading connection scoping template calls like these, they are not that hard to read.


DAO Manager Transaction Scoping

You can add a transaction() method similar to the executeAndClose() method which takes care of transaction management. Here is a sketch for such a method:

public class DaoManager{
  ...

  public Object transaction(DaoCommand command){
    try{
        this.connection.setAutoCommit(false);
        Object returnValue = command.execute(this);
        this.connection.commit();
        return returnValue;
    } catch(Exception e){
      this.connection.rollback();
      throw e; //or wrap it before rethrowing it
    } finally {
      this.connection.setAutoCommit(true);
    }
  }
}

The method sketched here does not preserve all exceptions thrown within the try-catch-finally block. For instance, if both commit() and rollback() throws exceptions, both of these exception are not properly preserved or handled. To do so would require a bit more code. This is left out for clarity here, though.

Using the transaction() method is analogous to using the executeAndClose() method:

DaoManager daoManager = daoFactory.createDaoManager();

daoManager.transaction(new DaoCommand(){

  public Object execute(DaoManager manager){
    Person person = manager.getPersonDao().readPerson(666);
    person.setLastName("Nick");
    manager.getPersonDao().updatePerson(person);
  }

});

This example reads a Person instance, changes the last name and updates the Person instance again. This is done within a tranaction.

Notice that the example does not close the connection. This could be done by wrapping the call to transaction() inside the call to executeAndClose(). Here is a method in the DaoManager that does that:

public class DaoManager{
  ...

  public Object transactionAndClose(DaoCommand command){
    executeAndClose(new DaoCommand(){
      public Object execute(DaoManager manager){
        manager.transaction(command);
      }
    });
  }
}

As you can see a DaoManager class can solve the problems of marking both connection life span and transaction boundaries, and automatically open and close connections and commit / rollback transactions. It also nicely centralizes the exception handling necessary for transaction management.


Single Point of Access for DAO's

The DaoManager also solves another problem in larger applications: The problem of finding out what DAO's already exists in the application. All DAO's can be made available from the DaoManager. This makes it much easier to find and reuse existing DAO's in large projects. Whether you actually want to do so is another issue. Reusing DAO methods througout a large application creates dependencies which may be hard to track. If you change a DAO method it may impact code elsewhere in the application which you might not have anticipated.


Hiding the Scope Boundary Code

As of now the DaoManager is visible in your domain logic. To recap, here is how using the DaoManager from your domain logic looks:

DaoManager daoManager = daoFactory.createDaoManager();

daoManager.transaction(new DaoCommand(){

  public Object execute(DaoManager manager){
   
    Person person = manager.getPersonDao().readPerson(666);
    person.setLastName("Nick");
    manager.getPersonDao().updatePerson(person);
   
  }
});

Notice how it is only really the code in bold that is of interest to us. The rest is just transaction demarcation code. If you are like me, you'll find that a bit "noisy". Luckily it is possible to hide this code.

In many applications your domain logic is implemented as some kind of event listener. In desktop applications your domain logic is typically activated by user events (keyboard / mouse). In web applications your domain logic is typically activated by an HTTP request. If you implement a base event listener class that all event listeners (or actions, or whatever your framework calls them) extend, you can put the DaoManager code in that class (or a subclass of the base class). Here is an example of such a class:

public class PersistenceActionBase {

  protected DaoManager daoManager = null;

  public PersistenceActionBase(DaoManager manager){
    this.daoManager = manager;
  }

  public void doAction() {
    this.daoManager.transactionAndClose(new DaoCommand(){
      public Object execute(DaoManager manager){
        doPersistenceAction(manager);
      }
    });
  }

  protected void doPersistenceAction(DaoManager manager){
    //override this method in subclasses.
  }
}

Here is an example of a subclass that executes the persistence code marked in bold in the first code box in this section:

public MyPersistenceAction extends PersistenceActionBase {

  public MyPersistenceAction(DaoManager manager){
    super(manager);
  }

  public void doPersistenceAction(DaoManager manager){
    
     Person person = manager.getPersonDao().readPerson(666);
     person.setLastName("Nick");
     manager.getPersonDao().updatePerson(person);
    
  }

}

Now your domain logic class only contains the persistence code that is actually interesting.

It may not always be possible or feasible to implement such a persistence action base class. It depends on whatever else goes on in an action etc. But you can still let yourself inspire by the idea, and save it for when it will work for you.


Lazy Opening of Connection

In most applications you will obtain the database connection from a connection pool. When that is the case you should not hold on to a connection longer than necessary. The longer you hold on to the connection, the longer other threads may have to wait to obtain that connection afterwards. In other words you should open the connection as late as possible and close it (returning it to the pool) as soon as possible.

When you hide the connection and transaction scope boundaries as explained in the previous section you are not actually opening the connection as late as possible. You are opening the connection when the DaoManager is created, which is when the persistence action is created.

Normally an action needs to do a bit of validation before accessing the database. It would be tempting to put that validation code inside the doPersistenceAction() method. But remember, a connection has been opened already when the DaoManager is instantiated, which happens before the doPersistenceAction() method is called. You should not open the connection until you need to use it the first time, which is not until the validation is complete. Furthermore, if the validation fails and aborts the doPersistenceAction() method call, you have opened a connection without ever using it. Of course it is closed again automatically, but it is still a waste of opening and closing a connection, pooled or not.

To avoid opening connections until you actually need it you can change the DaoManager. Instead of having a connection injected at instantiation time you will inject a DataSource or similar construct instead. If you are using a persistence API you will inject whatever class you obtain connections or their equivalents from (sessions in Hibernate, IDaos in Butterfly Persistence). Here is a sketch of that:

public class DaoManager{
  protected DataSource dataSource = null;
  protected Connection connection = null;

  protected PersonDao  personDao  = null;

  public DaoManager(DataSource dataSource){
    this.dataSource = dataSource;
  }

  public PersonDao getPersonDaoTx(){
    if(this.personDao == null){
      this.personDao = new PersonDao(getTxConnection());
    }
    return this.personDao;
  }

  protected Connection getConnection(){
    if(this.connection == null){
      this.connection = dataSource.getConnection();
    }
  }

  protected Connection getTxConnection(){
    getConnection().setAutoCommit(false);
  }

  public Object transaction(DaoCommand command){
    try{
        Object returnValue = command.execute(this);
        getConnection().commit();
        return returnValue;
    } catch(Exception e){
      getConnection().rollback();
      throw e; //or wrap it before rethrowing it
    } finally {
      getConnection().setAutoCommit(true);
    }
  }

  public Object executeAndClose(DaoCommand command){
    try{
      return command.execute(this);
    } finally {
      getConnction().close();
    }
  }

  public Object transactionAndClose(DaoCommand command){
    executeAndClose(new DaoCommand(){
      public Object execute(DaoManager manager){
        manager.transaction(command);
      }
    });
  }
}

Notice how the transaction() method has been changed a little. It no longer calls connection.setAutoCommit(false). This is now done instead from the getTxConnection() method. This is done to avoid obtaining the connection before the DaoCommand.execute() method is called, to postpone obtaining the connection as much as possible. Inside the DaoCommand.execute() method the getPersonDaoTx() will be called, and then getConnectionTx() will be called, and then connection.setAutoCommit(false) will be called at that time.

Here is a sketch of the call sequence:

domain layer --> daoFactory.createDaoManager()
domain layer --> daoManager.transactionAndClose()
 daoManager.transactionAndClose() --> daoManager.executeAndClose()
  daoManager.executeAndClose() --> daoManager.transaction()
   daoManager.transaction() --> command.execute()
    command.execute() --> validation code - may about execute() here
    command.execute() --> daoManager.getPersonDaoTx()
     daoManager.getPersonDaoTx() --> daoManager.getTxConnection();
      daoManager.getTxConnection() --> daoManager.getConnection();
       daoManager.getConnection() --> check if a connection exists.
                                      If yes, return it. If no, open new.
      daoManager.getTxConnection() --> connection.setAutoCommit(false);
   daoManager.transaction() --> daoManager.getConnection().commit()
  daoManager.executeAndClose() --> daoManager.getConnection().close();

It's a bit complicated, but once you get your mind around it, it is actually not that hard. And it solves the problem of transaction demarcation, and not obtaining a database connection until you actually need it, if you need it.


NextNext:   Advanced Connection and Transaction Demarcation and Propagation

Connect with me:
     
Newsletter - Get all my free tips!