The Java EE 7 Tutorial
37.3 Managing Entities
Entities are managed by the entity manager, which is represented by javax.persistence.EntityManager
instances. Each EntityManager
instance is associated with a persistence context: a set of managed entity instances that exist in a particular data store. A persistence context defines the scope under which particular entity instances are created, persisted, and removed. The EntityManager
interface defines the methods that are used to interact with the persistence context.
37.3.1 The EntityManager Interface
The EntityManager
API creates and removes persistent entity instances, finds entities by the entity's primary key, and allows queries to be run on entities.
37.3.1.1 Container-Managed Entity Managers
With a container-managed entity manager, an EntityManager
instance's persistence context is automatically propagated by the container to all application components that use the EntityManager
instance within a single Java Transaction API (JTA) transaction.
JTA transactions usually involve calls across application components. To complete a JTA transaction, these components usually need access to a single persistence context. This occurs when an EntityManager
is injected into the application components by means of the javax.persistence.PersistenceContext
annotation. The persistence context is automatically propagated with the current JTA transaction, and EntityManager
references that are mapped to the same persistence unit provide access to the persistence context within that transaction. By automatically propagating the persistence context, application components don't need to pass references to EntityManager
instances to each other in order to make changes within a single transaction. The Java EE container manages the lifecycle of container-managed entity managers.
To obtain an EntityManager
instance, inject the entity manager into the application component:
@PersistenceContext EntityManager em;
37.3.1.2 Application-Managed Entity Managers
With an application-managed entity manager, on the other hand, the persistence context is not propagated to application components, and the lifecycle of EntityManager
instances is managed by the application.
Application-managed entity managers are used when applications need to access a persistence context that is not propagated with the JTA transaction across EntityManager
instances in a particular persistence unit. In this case, each EntityManager
creates a new, isolated persistence context. The EntityManager
and its associated persistence context are created and destroyed explicitly by the application. They are also used when directly injecting EntityManager
instances can't be done because EntityManager
instances are not thread-safe. EntityManagerFactory
instances are thread-safe.
Applications create EntityManager
instances in this case by using the createEntityManager
method of javax.persistence.EntityManagerFactory
.
To obtain an EntityManager
instance, you first must obtain an EntityManagerFactory
instance by injecting it into the application component by means of the javax.persistence.PersistenceUnit
annotation:
@PersistenceUnit EntityManagerFactory emf;
Then obtain an EntityManager
from the EntityManagerFactory
instance:
EntityManager em = emf.createEntityManager();
Application-managed entity managers don't automatically propagate the JTA transaction context. Such applications need to manually gain access to the JTA transaction manager and add transaction demarcation information when performing entity operations. The javax.transaction.UserTransaction
interface defines methods to begin, commit, and roll back transactions. Inject an instance of UserTransaction
by creating an instance variable annotated with @Resource
:
@Resource UserTransaction utx;
To begin a transaction, call the UserTransaction.begin
method. When all the entity operations are complete, call the UserTransaction.commit
method to commit the transaction. The UserTransaction.rollback
method is used to roll back the current transaction.
The following example shows how to manage transactions in an application that uses an application-managed entity manager:
@PersistenceUnit EntityManagerFactory emf; EntityManager em; @Resource UserTransaction utx; ... em = emf.createEntityManager(); try { utx.begin(); em.persist(SomeEntity); em.merge(AnotherEntity); em.remove(ThirdEntity); utx.commit(); } catch (Exception e) { utx.rollback(); }
37.3.1.3 Finding Entities Using the EntityManager
The EntityManager.find
method is used to look up entities in the data store by the entity's primary key:
@PersistenceContext EntityManager em; public void enterOrder(int custID, CustomerOrder newOrder) { Customer cust = em.find(Customer.class, custID); cust.getOrders().add(newOrder); newOrder.setCustomer(cust); }
37.3.1.4 Managing an Entity Instance's Lifecycle
You manage entity instances by invoking operations on the entity by means of an EntityManager
instance. Entity instances are in one of four states: new, managed, detached, or removed.
-
New entity instances have no persistent identity and are not yet associated with a persistence context.
-
Managed entity instances have a persistent identity and are associated with a persistence context.
-
Detached entity instances have a persistent identity and are not currently associated with a persistence context.
-
Removed entity instances have a persistent identity, are associated with a persistent context, and are scheduled for removal from the data store.
37.3.1.5 Persisting Entity Instances
New entity instances become managed and persistent either by invoking the persist
method or by a cascading persist
operation invoked from related entities that have the cascade=PERSIST
or cascade=ALL
elements set in the relationship annotation. This means that the entity's data is stored to the database when the transaction associated with the persist
operation is completed. If the entity is already managed, the persist
operation is ignored, although the persist
operation will cascade to related entities that have the cascade
element set to PERSIST
or ALL
in the relationship annotation. If persist
is called on a removed entity instance, the entity becomes managed. If the entity is detached, either persist
will throw an IllegalArgumentException
, or the transaction commit will fail. The following method performs a persist
operation:
@PersistenceContext EntityManager em; ... public LineItem createLineItem(CustomerOrder order, Product product, int quantity) { LineItem li = new LineItem(order, product, quantity); order.getLineItems().add(li); em.persist(li); return li; }
The persist
operation is propagated to all entities related to the calling entity that have the cascade
element set to ALL
or PERSIST
in the relationship annotation:
@OneToMany(cascade=ALL, mappedBy="order") public Collection<LineItem> getLineItems() { return lineItems; }
37.3.1.6 Removing Entity Instances
Managed entity instances are removed by invoking the remove
method or by a cascading remove
operation invoked from related entities that have the cascade=REMOVE
or cascade=ALL
elements set in the relationship annotation. If the remove
method is invoked on a new entity, the remove
operation is ignored, although remove
will cascade to related entities that have the cascade
element set to REMOVE
or ALL
in the relationship annotation. If remove
is invoked on a detached entity, either remove
will throw an IllegalArgumentException
, or the transaction commit will fail. If invoked on an already removed entity, remove
will be ignored. The entity's data will be removed from the data store when the transaction is completed or as a result of the flush
operation.
In the following example, all LineItem
entities associated with the order are also removed, as CustomerOrder.getLineItems
has cascade=ALL
set in the relationship annotation:
public void removeOrder(Integer orderId) { try { CustomerOrder order = em.find(CustomerOrder.class, orderId); em.remove(order); }...
37.3.1.7 Synchronizing Entity Data to the Database
The state of persistent entities is synchronized to the database when the transaction with which the entity is associated commits. If a managed entity is in a bidirectional relationship with another managed entity, the data will be persisted, based on the owning side of the relationship.
To force synchronization of the managed entity to the data store, invoke the flush
method of the EntityManager
instance. If the entity is related to another entity and the relationship annotation has the cascade
element set to PERSIST
or ALL
, the related entity's data will be synchronized with the data store when flush
is called.
If the entity is removed, calling flush
will remove the entity data from the data store.
37.3.2 Persistence Units
A persistence unit defines a set of all entity classes that are managed by EntityManager
instances in an application. This set of entity classes represents the data contained within a single data store.
Persistence units are defined by the persistence.xml
configuration file. The following is an example persistence.xml
file:
<persistence> <persistence-unit name="OrderManagement"> <description>This unit manages orders and customers. It does not rely on any vendor-specific features and can therefore be deployed to any persistence provider. </description> <jta-data-source>jdbc/MyOrderDB</jta-data-source> <jar-file>MyOrderApp.jar</jar-file> <class>com.widgets.CustomerOrder</class> <class>com.widgets.Customer</class> </persistence-unit> </persistence>
This file defines a persistence unit named OrderManagement
, which uses a JTA-aware data source, jdbc/MyOrderDB
. The jar-file
and class
elements specify managed persistence classes: entity classes, embeddable classes, and mapped superclasses. The jar-file
element specifies JAR files that are visible to the packaged persistence unit that contain managed persistence classes, whereas the class
element explicitly names managed persistence classes.
The jta-data-source
(for JTA-aware data sources) and non-jta-data-source
(for non-JTA-aware data sources) elements specify the global JNDI name of the data source to be used by the container.
The JAR file or directory whose META-INF
directory contains persistence.xml
is called the root of the persistence unit. The scope of the persistence unit is determined by the persistence unit's root. Each persistence unit must be identified with a name that is unique to the persistence unit's scope.
Persistent units can be packaged as part of a WAR or EJB JAR file or can be packaged as a JAR file that can then be included in an WAR or EAR file.
-
If you package the persistent unit as a set of classes in an EJB JAR file,
persistence.xml
should be put in the EJB JAR'sMETA-INF
directory. -
If you package the persistence unit as a set of classes in a WAR file,
persistence.xml
should be located in the WAR file'sWEB-INF/classes/META-INF
directory. -
If you package the persistence unit in a JAR file that will be included in a WAR or EAR file, the JAR file should be located in either
-
The
WEB-INF/lib
directory of a WAR -
Or the EAR file's library directory
Note:
In the Java Persistence API 1.0, JAR files could be located at the root of an EAR file as the root of the persistence unit. This is no longer supported. Portable applications should use the EAR file's library directory as the root of the persistence unit.
-