A persistence context is a set of entities such that for any persistent identity
there is a unique entity instance. Within a persistence context, entities are
managed. The EntityManager
controls
their lifecycle, and they can access datastore resources.
When a persistence context ends, previously-managed entities become
detached. A detached entity is no longer under the control of the
EntityManager
, and no longer has access to datastore
resources. We discuss detachment in detail in
Section 2, “
Entity Lifecycle Management
”. For now, it is sufficient to
know that detachment has two obvious consequences:
The detached entity cannot load any additional persistent state.
The EntityManager
will not return the detached entity
from find
, nor will queries include the detached
entity in their results. Instead, find
method
invocations and query executions that would normally incorporate the detached
entity will create a new managed entity with the same identity.
OpenJPA offers several features related to detaching entities. See
Section 1, “
Detach and Attach
” in the Reference Guide.
Section 1.3, “
Defining the Detached Object Graph
” in particular describes how to
use the DetachState
setting to boost the performance of
merging detached entities.
Injected EntityManager
s have a transaction
persistence context,
while EntityManager
s obtained through the
EntityManagerFactory
have an extended
persistence context. We describe these persistence context types
below.
Under the transaction persistence context model, an EntityManager
begins a new persistence context with each transaction, and ends
the context when the transaction commits or rolls back. Within the transaction,
entities you retrieve through the EntityManager
or via
Queries
are managed entities. They can access datastore
resources to lazy-load additional persistent state as needed, and only one
entity may exist for any persistent identity.
When the transaction completes, all entities lose their association with the
EntityManager
and become detached. Traversing a
persistent field that wasn't already loaded now has undefined results. And using
the EntityManager
or a Query
to
retrieve additional objects may now create new instances with the same
persistent identities as detached instances.
If you use an EntityManager
with a transaction
persistence context model outside of an active transaction, each method
invocation creates a new persistence context, performs the method action, and
ends the persistence context. For example, consider using the
EntityManager.find
method outside of a transaction. The
EntityManager
will create a temporary persistence context, perform
the find operation, end the persistence context, and return the detached result
object to you. A second call with the same id will return a second detached
object.
When the next transaction begins, the EntityManager
will
begin a new persistence context, and will again start returning managed
entities. As you'll see in Chapter 8,
EntityManager
, you can
also merge the previously-detached entites back into the new persistence
context.
Example 7.1. Behavior of Transaction Persistence Context
The following code illustrates the behavior of entites under an
EntityManager
using a transaction persistence context.
EntityManager em; // injected ... // outside a transaction: // each operation occurs in a separate persistence context, and returns // a new detached instance Magazine mag1 = em.find(Magazine.class, magId); Magazine mag2 = em.find(Magazine.class, magId); assertTrue(mag2 != mag1); ... // transaction begins: // within a transaction, a subsequent lookup doesn't return any of the // detached objects. however, two lookups within the same transaction // return the same instance, because the persistence context spans the // transaction Magazine mag3 = em.find(Magazine.class, magId); assertTrue(mag3 != mag1 && mag3 != mag2); Magazine mag4 = em.find(Magazine.class (magId); assertTrue(mag4 == mag3); ... // transaction commits: // once again, each operation returns a new instance Magazine mag5 = em.find(Magazine.class, magId); assertTrue(mag5 != mag3);
An EntityManager
using an extended persistence context
maintains the same persistence context for its entire lifecycle. Whether inside
a transaction or not, all entities returned from the EntityManager
are managed, and the EntityManager
never
creates two entity instances to represent the same persistent identity. Entities
only become detached when you finally close the EntityManager
(or when they are serialized).
Example 7.2. Behavior of Extended Persistence Context
The following code illustrates the behavior of entites under an
EntityManager
using an extended persistence context.
EntityManagerFactory emf = ... EntityManager em = emf.createEntityManager(); // persistence context active for entire life of EM, so only one entity // for a given persistent identity Magazine mag1 = em.find(Magazine.class, magId); Magazine mag2 = em.find(Magazine.class, magId); assertTrue(mag2 == mag1); em.getTransaction().begin(); // same persistence context active within the transaction Magazine mag3 = em.find(Magazine.class, magId); assertTrue(mag3 == mag1); Magazine mag4 = em.find(Magazine.class (magId); assertTrue(mag4 == mag1); em.getTransaction.commit (); // when the transaction commits, instance still managed Magazine mag5 = em.find(Magazine.class, magId); assertTrue(mag5 == mag1); // instance finally becomes detached when EM closes em.close();