JDO Persistence, Part 2
|
Related Reading
Java Database Best Practices |
Editor's note: In part one in this three-part series on JDO persistence, excerpted from Java Database Best Practices, George Reese described all of the available persistence options for Java architects and developers. In part two this week, George covers JDO persistence best practices for transaction management and query control.
Basic JDO Persistence
Most JDO applications fall into the small-to-medium scale. In general, you have a simple to moderately complex domain model built into any one of the following kinds of architectures:
- Web application
- Server application
- Two-tier client/server
The tutorial in Chapter 12 ("TITLE") covers the basics of building such an application.
Transaction Management
Though JDO persistence is designed to be transparent to the business
component developer, it is not transparent to the application developer. The
examples in Chapter 12 show only how to manage persistent objects in the main( ) method of a contrived application. In reality, you
will be managing persistent objects through JSPs and servlets, Swing components,
and even other persistent objects.
Figure 7-1 shows how JDO might interact with a web application. The JSP views
perform queries and display data from the persistent objects. Controllers
create, modify, and delete the persistent objects. In other words, the JSP pages
perform the same role as the main( ) method from
Chapter 12's examples.
Figure 7-1. JDO in a simplistic web application

This approach works and you will see no problems from it until your domain model begins growing in complexity. One of the drawbacks of JDO, however, is that it does not manage object relationships automatically--you are responsible for maintaining the integrity of all relationships among persistent objects. When you embed the logic for the creation and deletion of persistent objects in views and controllers, you create a maintenance problem.
For example, your web application could have two controllers: one that
deletes an author and another that deletes a book. Each controller would require
code that not only calls deletePersistent( ), but
that also protects the integrity of the relationship between Author and Book. If the rules
governing this relationship change, you need to make sure you find all places in
the application where the relationship is being managed and make the appropriate
changes.
To diminish the risk of managing relationships in your application, you need to centralize the logic for managing your persistent object relationships. I recommend the creation of an EJB session bean-like class that performs metaoperations on your persistent classes. Example 7-1 shows such a class.
|
Example 7-1: A Bookshelf class to manage object relationships
package com.imaginary.ora;
import javax.jdo.*;
public abstract class Bookshelf {
static private PersistenceManager getPersistenceManager( ) {
PersistenceManagerFactory factory;
Properties props = new Properties( );
// load JDO properties
factory = JDOHelper.getPersistenceManagerFactory(props);
return factory.getPersistenceManager( );
}
static public void createAuthor(Author auth) {
PersistenceManager mgr = getPersistenceManager( );
Transaction trans;
trans = mgr.currentTransaction( );
trans.setOptimistic(false);
try {
trans.begin( );
mgr.makePersistent(auth);
trans.commit( );
}
catch( Exception e ) {
e.printStackTrace( );
}
finally {
if( trans.isActive( ) ) {
trans.rollback( );
}
mgr.close( );
}
}
static public void deleteAuthor(Author auth) {
PersistenceManager mgr = getPersistenceManager( );
Transaction trans;
trans = mgr.currentTransaction( );
try { trans.setOptimistic(true); }
catch( JDOUnsupportedOptionException e ) { }
try {
Iterator books = auth.getBooks( ).iterator( );
trans.begin( );
while( it.hasNext( ) ) {
mgr.deletePersistent((Book)it.next( ));
}
mgr.deletePersistent(auth);
trans.commit( );
}
catch( Exception e ) {
e.printStackTrace( );
}
finally {
if( trans.isActive( ) ) {
trans.rollback( );
}
mgr.close( );
}
}
static public void createBook(Author auth, Book book) {
PersistenceManager mgr = getPersistenceManager( );
Transaction trans;
trans = mgr.currentTransaction( );
try { trans.setOptimistic(true); }
catch( JDOUnsupportedOptionException e ) { }
try {
trans.begin( );
book.setAuthor(auth);
auth.addBook(book);
mgr.makePersistent(book);
trans.commit( );
}
catch( Exception e ) {
e.printStackTrace( );
}
finally {
if( trans.isActive( ) ) {
trans.rollback( );
}
mgr.close( );
}
}
static public void deleteBook(Book book) {
PersistenceManager mgr = getPersistenceManager( );
Transaction trans;
trans = mgr.currentTransaction( );
try { trans.setOptimistic(true); }
catch( JDOUnsupportedOptionException e ) { }
try {
trans.begin( );
book.getAuthor( ).removeBook(book);
mgr.deletePersistent(book);
trans.commit( );
}
catch( Exception e ) {
e.printStackTrace( );
}
finally {
if( trans.isActive( ) ) {
trans.rollback( );
}
mgr.close( );
}
}
}
This class performs two critical tasks:
It clearly demarcates the boundaries of transactions involving
AuthorandBookinstances.It centralizes all logic relating to the management of
AuthorandBookrelationships.
It also has the hidden benefit of making the persistence model transparent to your controller classes. The JSP code to create a new author looks like this:
<% Bookshelf.createAuthor(new Author(firstName, lastName)); %>
This code also uses optimistic transaction management for optimal performance. In doing so, it checks for the possibility that the JDO implementation does not support optimistic transaction management. Not all JDO implementations support optimistic transaction management, and not all transactions are well suited to optimistic transaction management. In general, optimistic transaction management works when you are performing multiple operations and each operation targets a different object.
The exception in this example was the code to create a new Author. Because the operation touched only the Author class for a single operation, it is going to see
better performance under data store transaction management.
|
Query Control
The previous section made the use of JDO transparent to controllers--views
still use JDO queries to retrieve collections of persistent objects. This issue
is not the maintenance problem that running creates and deletes in multiple
locations produced. It would nevertheless be nice to centralize query logic to
provide view pages with the same transparency as well as give us a single
location to tweak query logic. The Bookshelf class
looks like a good candidate. On the other hand, it probably makes more sense to
have a one-to-one association between a persistent class and the class that
manages its queries. Example 7-2 shows an AuthorFinder class to handle
queries.
Example 7-2: A class that centralizes query logic for Author instances
package com.imaginary.ora;
import java.util.*;
import javax.jdo.*;
public abstract class AuthorFinder {
static private final String GENRE = "gen";
static private final String YEAR = "yr";
static public Collection findByGenreYear(String gen, int yr) {
Extent ext = mgr.getExtent(Author.class, true);
Query query = mgr.newQuery(ext,
"books.contains(book) & (book.year=yr & book.genre = gen)");
HashMap params = new HashMap( );
query.declareParameters("int yr, String gen");
query.declareVariables("com.imaginary.ora.Book book");
params.put(GENRE, gen);
params.put(YEAR, yr);
return(Collection)query.executeWithMap(params);
}
}
This example provides a single query, but in reality it will likely contain a
variety of queries to help support various Author
searches. This particular query provides the application with a list of all
authors who published a book of a specific genre in a specific year. Even though
the search has only two parameters, I used executeWithMap( ) because it helps prevent any maintenance ugliness associated with
matching parameter order.
|
Next week, in the third and final installment in this series of excerpts on JDO Persistence, George Reese will cover persisting EJBs as part of a bean-managed persistence.
George Reese is the founder of two Minneapolis-based companies, enStratus Networks LLC (maker of high-end cloud infrastructure management tools) and Valtira LLC (maker of the Valtira Online Marketing Platform). He is also the author of technology books such as the MySQL Pocket Reference, Database Programming with JDBC and Java, and Java Database Best Practices.
Return to ONJava.com.