The diagram below illustrates the relationships between the primary components of the JDO architecture.
JDOHelper
:
The javax.jdo.JDOHelper
contains static
helper methods to query the lifecycle state of persistent
objects and to obtain
PersistenceManagerFactory
instances in a
vendor-neutral fashion.
PersistenceManagerFactory
: The javax.jdo.PersistenceManagerFactory
is a factory for
PersistenceManager
s.
PersistenceManager
:
The javax.jdo.PersistenceManager
is the
primary JDO interface used by applications. Each
PersistenceManager
manages a set of
persistent objects, and has APIs to insert new objects and
delete existing ones. There is a one-to-one
relationship between a PersistenceManager
and a Transaction
.
PersistenceManager
s also act as factories
for Extent
and
Query
instances.
PersistenceCapable
:
JDO calls user-defined persistent classes
persistence-capable classes. Most JDO vendors provide
an enhancer to transparently add a special
PersistenceCapable
interface to each
persistent class. You will never use this interface directly.
Transaction
:
Each PersistenceManager
has a one-to-one
relation with a single javax.jdo.Transaction
.
Transaction
s allow operations on persistent
data to be grouped into units of work that either completely
succeed or completely fail, leaving the datastore in its original
state. These all-or-nothing operations are important for
maintaining data integrity.
Extent
: A
javax.jdo.Extent
is a logical view of
all the objects of a particular class that exist in the
datastore. You can configure Extent
s
to also include subclasses. Extent
s
are obtained from a PersistenceManager
.
Query
: The
javax.jdo.Query
interface is implemented
by each JDO vendor to find persistent objects that meet certain
criteria. JDO standardizes support for queries using the Java
Data Objects Query Language (JDOQL), and for relational database
queries using the Structured Query Language (SQL). You obtain
Query
instances from a
PersistenceManager
.
FetchPlan
:
Each PersistenceManager
and
Query
has a mutable reference to a
javax.jdo.FetchPlan
. The
FetchPlan
gives you control over eager
fetching, result scrolling, and other data loading behavior.
Sequence
: The
javax.jdo.datastore.Sequence
interface
represents an object capable of generating sequential values.
Sequences are defined in mapping metadata (see
Chapter 15, Mapping Metadata), cached at the
PersistenceManagerFactory
level, and
obtained through the PersistenceManager
.
DataStoreCache
: Many
JDO implementations provide some form of datastore cache.
The javax.jdo.datastore.DataStoreCache
interface provides a standard way to interact with your vendor's
cache.
The example below illustrates how the JDO interfaces interact to execute a JDOQL query and update persistent objects.
Example 3.1. Interaction of JDO Interfaces
// get a PersistenceManagerFactory using the JDOHelper; typically // the factory is cached for easy repeated use PersistenceManagerFactory factory = JDOHelper.getPersistenceManagerFactory (System.getProperties ()); // get a PersistenceManager from the factory PersistenceManager pm = factory.getPersistenceManager (); // updates take place within transactions Transaction tx = pm.currentTransaction (); tx.begin (); // query for all employees who work in our research division // and put in over 40 hours a week average Extent extent = pm.getExtent (Employee.class, false); Query query = pm.newQuery (extent); query.setFilter ("division.name == 'Research' && avgHours > 40"); // we only need to populate the metadata-defined salary fetch group data; // there might be a lot of employees, so read from store in batches of 100 query.getFetchPlan ().setGroup ("salary"); query.getFetchPlan ().setFetchSize (100); List results = (List) query.execute (); // give all those hard-working employees a raise; keep track of hardest worker Employee emp; Employee mostHours = null; for (Iterator itr = results.iterator (); itr.hasNext ();) { emp = (Employee) itr.next (); emp.setSalary (emp.getSalary () * 1.1); if (mostHours == null || emp.avgHours () > mostHours.avgHours ()) mostHours = emp; } // we know we're going to be fetching the hardest-working employee a // lot in our application, so pin its data to the cache factory.getDataStoreCache ().pin (JDOHelper.getObjectId (mostHours)); // commit the updates and free persistence manager tx.commit (); pm.close (); // if we were ending our application, we'd free the factory too // factory.close ();
The remainder of this document explores the JDO interfaces in detail. We present them in roughly the order that you will use them as you develop your application.
The diagram above depicts the JDO exception architecture. Runtime
exceptions such as NullPointerException
s and
IllegalArgumentException
s aside, JDO
components only throw
JDOException
s.
The JDO exception hierarchy should be self-explanatory. The base
JDOException
class provides the following useful
properties:
FailedObject
: The failed object is the
persistent instance or identity object that caused the
exception, if applicable. It is particularly useful for
JDOOptimisticVerificationException
s and
JDOObjectNotFoundException
s.
NestedExceptions
: An array of nested
exceptions that caused the failure. Rather than stop
immediately at the first error, many JDO methods collect all
errors during execution and throw a single parent exception,
nesting the collected exceptions within it. For example, a
failed attempt to commit a transaction might result in a
JDOFatalDataStoreException
with a nested
JDOOptimisticVerificationException
for
each persistent instance that failed the optimsitic concurrency
check.
See the Javadoc for additional details on JDO exceptions.