DekGenius.com
[ Team LiB ] Previous Section Next Section

8.3 Persistence Operations

The Author and Book classes in Example 8-1 and Example 8-2 do not contain any persistence-related methods. Both Castor and Hibernate, however, require you to add code to trigger persistence operations.

With any database-intensive application, the flushing of new state to the database is a time-expensive process. One advantage to controlling when the flushing of your data occurs is that you can manage this expense.

With both persistence systems, persistence operations are done by loading the mapping files, obtaining a database connection, calling for an object to be persisted, and closing out the transaction. Abstracting the persistence code with a data access object will help you create a cleaner implementation.

BEST PRACTICE: Encapsulate persistence operations using both frameworks in data access objects similar to those we have used in other persistence models in this book. This will allow you to easily refactor your code to an alternative persistence system such as EJBs.

8.3.1 Castor Persistence

In our example, we need the ability to add a new book to an author's list of books. In Castor, the method to perform this task might look like this:

public Book addBook (Book book) throws Exception {
     JDO jdo = new JDO("alternativepersistencedb");
     jdo.loadConfiguration("database.xml");
     Database db = jdo.getDatabase( );
     db.begin( );
     db.create(book);
     db.commit( );
     db.close( );
     return book;     
}

BEST PRACTICE: Using a singleton to manage the loading and parsing of your persistence configuration files will increase the speed of your persistence operations.

This code references a new XML file, the database.xml configuration file. It describes your database connections to enable Castor to access a JDBC data source. Example 8-5 shows what such a file looks like.

Example 8-5. Castor database connection descriptor
<!DOCTYPE databases 
  PUBLIC "-//EXOLAB/Castor JDO Configuration DTD Version 1.0//EN" 
         "http://castor.exolab.org/jdo-conf.dtd">
   
<database name="aps" engine="sql-server">
    <driver class-name="net.sourceforge.jtds.jdbc.Driver" url="jdbc:jtds:sqlserver://
localhost:1433/aps">
        <param name="user" value="aps"/>
        <param name="password" value="research"/>
    </driver>
    <mapping href="mapping.xml"/>
</database>

With the connection information defined, a database session is established by calling the JDO class method getDatabase( ). To start a transaction, the begin( ) method is called on the Database session. The Book class is now ready to be persisted. This is accomplished by calling create( ) on the Database session. The new Book has been persisted, and connection cleanup needs to be performed by closing the transaction with commit( ) and close( ) on the Database session. If a transaction error occurs, a TransactionAbortedException will be thrown by the Database session.

8.3.2 Hibernate Persistence

Hibernate persistence works very much like Castor persistence. You basically have to make calls to methods with similar names in different classes:

public Book addBook (Book book) throws Exception {
     Datastore ds = Hibernate.createDatastore( );
     ds.storeFile("hibernate.xml");
     SessionFactory sessionFactory = ds.buildSessionFactory( );
     Session session = sessionFactory.openSession( );
     session.beginTransaction( );
     session.saveOrUpdate(book);
     session.flush( );
     session.connection( ).commit( );
     session.close( );     
}

The first line of code calls createDatastore( ), which loads the Hibernate connection descriptor (an example is provided in Example 8-6). An XML-based connection descriptor is also available.

Example 8-6. Hibernate database connection descriptor
hibernate.connection.driver_class=net.sourceforge.jtds.jdbc.Driver
hibernate.connection.url=jdbc:jtds:sqlserver://localhost:1433/aps
hibernate.connection.username=aps
hibernate.connection.password=research

With the connection information loaded, the storeFile( ) method then reads in the mapping descriptor. The SessionFactory is used to manage session connections across the application. For our example, we are creating the SessionFactory with each request. To start a transaction, the beginTransaction( ) method on the current Session is called. The saveOrUpdate( ) method is then called to create or update any object that needs to be persisted. The flush( ) must be called at the end of any transaction cycle. Flushing is used to synchronize the database with persistent objects in memory. To close the transaction, the commit( ) method is called, and the transaction is closed with the close( ) method. Transaction errors will throw a SQLException.

BEST PRACTICE: Both frameworks support database connection pooling or the use of JNDI data sources. Take advantage of this support in your database applications.

    [ Team LiB ] Previous Section Next Section