Java Persistence/Runtime

From Wikibooks, open books for an open world
Jump to: navigation, search

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]

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]

In JSE 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 JSE 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 JSE. 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 JSE. 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 JSE 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 JSE 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]

<?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>
 
        <!-- Hibernate -->
        <!--provider>org.hibernate.ejb.HibernatePersistence</provider-->
 
        <!-- TopLink Essentials -->
        <!--provider>oracle.toplink.essentials.PersistenceProvider</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]

<?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>
 
        <!-- Hibernate -->
        <!--provider>org.hibernate.ejb.HibernatePersistence</provider-->
 
        <!-- TopLink Essentials -->
        <!--provider>oracle.toplink.essentials.PersistenceProvider</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]

EntityManagerFactory factory = Persistence.createEntityManagerFactory("acme");
EntityManager entityManager =  factory.createEntityManager();
...
entityManager.close();

Java Enterprise Edition[edit]

In JEE 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 JEE 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 behavoir 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 JEE JPA persistence.xml file[edit]

<?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]

<?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]

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]

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]

@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]

(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);
    }
}

Stateless SessionBeans[edit]

Stateful SessionBeans[edit]