Java Persistence/Runtime
Once you have mapped your object model the second step in persistence development is to access and process your objects from your application, this is referred to as the runtime usage of persistence. Various persistence specifications have had various runtime models. The most common model is to have a runtime API; a runtime API typically will define API for connecting to a data-source, querying and transactions.
Entity Manager
[edit | edit source]JPA provides a runtime API defined by the javax.persistence
package. The main runtime class is the EntityManager
class. The EntityManager provides API for creating queries, accessing transactions, and finding, persisting, merging and deleting objects. The JPA API can be used in any Java environment including JSE and JEE.
An EntityManager can be created through an EntityManagerFactory
, or can be injected into an instance variable in an EJB SessionBean, or can be looked up in JNDI in a JEE server.
JPA is used differently in Java Standard Edition (JSE) versus Java Enterprise Edition (JEE).
Java Standard Edition
[edit | edit source]In Java SE an EntityManager
is accessed from the JPA Persistence
class through the createEntityManagerFactory
API. The persistent unit name is passed to the createEntityManagerFactory
, this is the name given in the persistence unit's persistence.xml
file. All Java SE JPA applications must define a persistence.xml
file. The file defines the persistence unit including the name, classes, orm files, datasource, vendor specific properties.
JPA 1.0 does not define a standard way of specifying how to connect to the database in Java SE. Each JPA provider defines their own persistence properties for setting the JDBC driver manager class, URL, user and password. JPA has a standard way of setting the DataSource
JNDI name, but this is mainly used in JEE.
JPA 2.0 does define standard persistence unit properties for connecting to JDBC in Java SE. These include, javax.persistence.jdbc.driver
, javax.persistence.jdbc.url
, javax.persistence.jdbc.user
, javax.persistence.jdbc.password
.
The JPA application is typically required to be packaged into a persistence unit jar file. This is a normal jar, that has the persistence.xml
file in the META-INF
directory. Typically a JPA provider will require something special be done in Java SE to enable certain features such as lazy fetching, such as static weaving (byte-code processing) of the jar, or using a Java agent JVM option.
In Java SE the EntityManager
must be closed when your application is done with it. The life-cycle of the EntityManager
is typically per client, or per request. The EntityManagerFactory
can be shared among multiple threads or users, but the EntityManager
should not be shared.
Example JPA 1.0 persistence.xml file
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd"
version="1.0">
<persistence-unit name="acme" transaction-type="RESOURCE_LOCAL">
<!-- EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- TopLink Essentials -->
<!--provider>oracle.toplink.essentials.PersistenceProvider</provider-->
<!-- Hibernate 3.x -->
<!--provider>org.hibernate.ejb.HibernatePersistence</provider-->
<!-- Hibernate -->
<!--provider>org.hibernate.jpa.HibernatePersistenceProvider</provider-->
<!-- Apache OpenJPA -->
<!--provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider-->
<!-- DataNucleus-->
<!--provider>org.datanucleus.jpa.PersistenceProviderImpl</provider-->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.jdbc.driver" value="org.acme.db.Driver"/>
<property name="eclipselink.jdbc.url" value="jdbc:acmedb://localhost/acme"/>
<property name="eclipselink.jdbc.user" value="wile"/>
<property name="eclipselink.jdbc.password" value="elenberry"/>
</properties>
</persistence-unit>
</persistence>
Example JPA 2.0 persistence.xml file
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_2_0.xsd"
version="2.0">
<persistence-unit name="acme" transaction-type="RESOURCE_LOCAL">
<!-- EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- TopLink Essentials -->
<!--provider>oracle.toplink.essentials.PersistenceProvider</provider-->
<!-- Hibernate 3.x -->
<!--provider>org.hibernate.ejb.HibernatePersistence</provider-->
<!-- Hibernate -->
<!--provider>org.hibernate.jpa.HibernatePersistenceProvider</provider-->
<!-- Apache OpenJPA -->
<!--provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider-->
<!-- DataNucleus -->
<!--provider>org.datanucleus.jpa.PersistenceProviderImpl</provider-->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.acme.db.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:acmedb://localhost/acme"/>
<property name="javax.persistence.jdbc.user" value="wile"/>
<property name="javax.persistence.jdbc.password" value="elenberry"/>
</properties>
</persistence-unit>
</persistence>
Example of accessing an EntityManager from an EntityManagerFactory
[edit | edit source]EntityManagerFactory factory = Persistence.createEntityManagerFactory("acme");
EntityManager entityManager = factory.createEntityManager();
...
entityManager.close();
Java Enterprise Edition
[edit | edit source]In Java EE the EntityManager
or EntityManagerFactory
can either be looked up in JNDI, or injected into a SessionBean
. To look up the EntityManager
in JNDI it must be published in JNDI such as through a <persistence-context-ref>
in a SessionBean
's ejb-jar.xml
file. To inject an EntityManager
or EntityManagerFactory
the annotation @PersistenceContext
or @PersistenceUnit
are used.
In Java EE an EntityManager
can either be managed (container-managed) or non-managed (application-managed). A managed EntityManager
has a different life-cycle than an EntityManager
managed by the application. A managed EntityManager
should never be closed, and integrates with JTA transactions so local transaction cannot be used. Across each JTA transaction boundary all of the entities read or persisted through a managed EntityManager
become detached. Outside of a JTA transaction a managed EntityManager
's behavior is sometimes odd, so typically should be used inside a JTA transaction.
A non-managed EntityManager
is one that is created by the application through a EntityManagerFactory
or directly from Persistence
. A non-managed EntityManager
must be closed, and typically does not integrate with JTA, but this is possible through the joinTransaction
API. The entities in a non-managed EntityManager
do not become detached after a transaction completes, and can continue to be used in subsequent transactions.
Example Java EE JPA persistence.xml file
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd"
version="1.0">
<persistence-unit name="acme" transaction-type="JTA">
<jta-data-source>jdbc/ACMEDataSource</jta-data-source>
</persistence-unit>
</persistence>
Example SessionBean ejb-jar.xml file with persistence context
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">
<enterprise-beans>
<session>
<ejb-name>EmployeeService</ejb-name>
<business-remote>org.acme.EmployeeService</business-remote>
<ejb-class>org.acme.EmployeeServiceBean</ejb-class>
<session-type>Stateless</session-type>
<persistence-context-ref>
<persistence-context-ref-name>persistence/acme/entity-manager</persistence-context-ref-name>
<persistence-unit-name>acme</persistence-unit-name>
</persistence-context-ref>
<persistence-unit-ref>
<persistence-unit-ref-name>persistence/acme/factory</persistence-unit-ref-name>
<persistence-unit-name>acme</persistence-unit-name>
</persistence-unit-ref>
</session>
</enterprise-beans>
</ejb-jar>
Example of looking up an EntityManager in JNDI from a SessionBean
[edit | edit source]InitialContext context = new InitialContext(properties);
EntityManager entityManager = (EntityManager)context.lookup("java:comp/env/persistence/acme/entity-manager");
...
Example of looking up an EntityManagerFactory in JNDI from a SessionBean
[edit | edit source]InitialContext context = new InitialContext(properties);
EntityManagerFactory factory = (EntityManagerFactory)context.lookup("java:comp/env/persistence/acme/factory");
...
Example of injecting an EntityManager and EntityManagerFactory in a SessionBean
[edit | edit source]@Stateless(name="EmployeeService", mappedName="acme/EmployeeService")
@Remote(EmployeeService.class)
public class EmployeeServiceBean implements EmployeeService {
@PersistenceContext(unitName="acme")
private EntityManager entityManager;
@PersistenceUnit(unitName="acme")
private EntityManagerFactory factory;
...
}
Example of lookup an EJBContext in an Entity
[edit | edit source](Useful for Audit)
protected EJBContext getContext() {
try {
InitialContext context = new InitialContext();
return (EJBContext)context.lookup("java:comp/EJBContext");
} catch (NamingException e) {
throw new EJBException(e);
}
}