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
PersistenceManagers.
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.
PersistenceManagers 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.
Transactions 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 Extents
to also include subclasses. Extents
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 NullPointerExceptions and
IllegalArgumentExceptions aside, JDO
components only throw
JDOExceptions.
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
JDOOptimisticVerificationExceptions and
JDOObjectNotFoundExceptions.
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.