Friday, November 27, 2009

8.3 Persistence Operations



[ Team LiB ]






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 ]



    No comments: