Multiple PersistenceManagers Accessing the Same Datastore

You can instantiate multiple PersistenceManagers in your application from the same or
different PersistenceManagerFactorys. Figure 3-3 illustrates an application with two PersistenceManagers from the same PersistenceManagerFactory.

Figure 3-3. Application with multiple PersistenceManagers

Each PersistenceManager manages its
own transaction context and application cache. In this particular example,
both PersistenceManagers access the same datastore
and are from the same JDO implementation. This is the typical architecture for
managed environments where different instances of the same component access
the same datastore via different PersistenceManagers.

Both PersistenceManagers may have the
same datastore instance in their caches, represented by different persistent
instances. This architecture provides for transactional isolation of changes
made to the same datastore instance by different transactions.

Multiple PersistenceManagers Accessing Different Datastores

Figure 3-4 illustrates PersistenceManagers accessing
different datastores. These PersistenceManagers
could be from the same or different implementations. For example, one
datastore may be a relational database and the other an object database. Due
to JDO's binary-compatibility contract (covered in Chapter 6), PersistenceManagers from different implementations can
manage different instances of the same persistent classes. JDO is the first
database-interface technology to offer this high level of portability across
database architectures.

Figure 3-4. Application with multiple JDO implementations

Shared Implementation Cache

In addition to the application cache, some JDO implementations
also maintain their own persistent instance cache that sits between the
application cache and the datastore. Your application does not have access to
this implementation cache. Its role is to cache the state of objects from the
datastore in memory, so they can be provided to the application without
requiring access to the datastore. Use of caches can result in significant
performance improvements. A shared implementation cache is most useful when
you use nontransactional access, covered in Chapter 14, or optimistic
transactions, covered in Chapter 15. When you use datastore transactions, the
shared cache is usually bypassed.

Shared implementation cache within a single JVM

Figure 3-5 illustrates a shared implementation cache that is managed within a
single JVM. It allows each of the PersistenceManagers to quickly access the state of
objects that have been accessed from the same datastore.

Figure 3-5. Implementation of a shared cache for transactions
accessing the same datastore

For example, if one PersistenceManager accesses a particular instance, the
implementation needs to read the instance from the datastore. But if the other
PersistenceManager then accesses the same instance,
the implementation can use the data in the shared implementation cache and
avoid having to access the datastore.

Shared implementation cache distributed among JVMs

Several JDO implementations provide a distributed cache
architecture, which allows them to migrate the state of objects between JVMs.
Figure 3-6 illustrates this architecture.

Figure 3-6. Implementation use of distributed, synchronized caches

Again, the goal with these implementations is to avoid a
datastore access whenever possible. For some systems where multiple
applications may access the same objects, these implementations demonstrate
substantial performance improvements.