Chapter 12. Java Persistence API (JPA)

12.1. About Java Persistence API (JPA)

The Java Persistence API (JPA) is a Java specification for accessing, persisting, and managing data between Java objects or classes and a relational database. The JPA specification recognizes the interest and the success of the transparent object or relational mapping paradigm. It standardizes the basic APIs and the metadata needed for any object or relational persistence mechanism.

Note

JPA itself is just a specification, not a product; it cannot perform persistence or anything else by itself. JPA is just a set of interfaces, and requires an implementation.

12.2. Create a Simple JPA Application

Follow the procedure below to create a simple JPA application in Red Hat CodeReady Studio.

  1. Create a JPA project in Red Hat CodeReady Studio.

    1. In Red Hat CodeReady Studio, click FileNewProject. Find JPA in the list, expand it, and select JPA Project. You are presented with the following dialog.

      Figure 12.1. New JPA Project Dialog

      This is the new JPA Project dialog.
    2. Enter a Project name.
    3. Select a Target runtime. If no target runtime is available, follow these instructions to define a new server and runtime: Downloading, Installing, and Setting Up JBoss EAP from within the IDE in the Getting Started with CodeReady Studio Tools guide.
    4. Under JPA version, ensure 2.1 is selected.
    5. Under Configuration, choose Basic JPA Configuration.
    6. Click Finish.
    7. If prompted, choose whether you wish to associate this type of project with the JPA perspective window.
  2. Create and configure a new persistence settings file.

    1. Open an EJB 3.x project in Red Hat CodeReady Studio.
    2. Right click the project root directory in the Project Explorer panel.
    3. Select NewOther…​.
    4. Select XML File from the XML folder and click Next.
    5. Select the ejbModule/META-INF/ folder as the parent directory.
    6. Name the file persistence.xml and click Next.
    7. Select Create XML file from an XML schema file and click Next.
    8. Select http://java.sun.com/xml/ns/persistence/persistence_2.0.xsd from the Select XML Catalog entry list and click Next.

      Figure 12.2. Persistence XML Schema

      Persistence XML Schema
    9. Click Finish to create the file. The persistence.xml has been created in the META-INF/ folder and is ready to be configured.

      Example: Persistence Settings File

      <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 http://java.sun.com/xml/ns/persistence/persistence_2_2.xsd"
         version="2.2">
         <persistence-unit name="example" transaction-type="JTA">
            <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
            <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
            <mapping-file>ormap.xml</mapping-file>
            <jar-file>TestApp.jar</jar-file>
            <class>org.test.Test</class>
            <shared-cache-mode>NONE</shared-cache-mode>
            <validation-mode>CALLBACK</validation-mode>
            <properties>
               <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
               <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            </properties>
         </persistence-unit>
      </persistence>

12.3. JPA Entities

Once you have established the connection from your application to the database, you can start mapping the data in the database to Java objects. Java objects that are used to map against database tables are called entity objects.

Entities have relationships with other entities, which are expressed through object-relational metadata. The object-relational metadata can be specified either directly in the entity class file by using annotations, or in an XML descriptor file called persistence.xml included with the application.

The high-level mapping of Java objects to the database is as follows:

  • Java classes map to the database tables.
  • Java instances map to the database rows.
  • Java fields map to the database columns.

12.4. Persistence Context

The JPA persistence context contains the entities managed by the persistence provider. The persistence context acts like a first level transactional cache for interacting with the datasource. It manages the entity instances and their lifecycle. Loaded entities are placed into the persistence context before being returned to the application. Entity changes are also placed into the persistence context to be saved in the database when the transaction commits.

The lifetime of a container-managed persistence context can either be scoped to a transaction, which is referred to as a transaction-scoped persistence context, or have a lifetime scope that extends beyond that of a single transaction, which is referred to as an extended persistence context. The PersistenceContextType property, which has the enum datatype, is used to define the persistence context lifetime scope for container-managed entity managers. The persistence context lifetime scope is defined when the EntityManager instance is created.

12.4.1. Transaction-Scoped Persistence Context

The transaction-scoped persistence context works with the active JTA transaction. When the transaction commits, the persistence context is flushed to the datasource; the entity objects are detached but might still be referenced by the application code. All the entity changes that are expected to be saved to the datasource must be made during a transaction. Entities that are read outside the transaction are detached when the EntityManager invocation completes.

12.4.2. Extended Persistence Context

The extended persistence context spans multiple transactions and allows data modifications to be queued without an active JTA transaction. The container-managed extended persistence context can only be injected into a stateful session bean.

12.5. JPA EntityManager

JPA entity manager represents a connection to the persistence context. You can read from and write to the database defined by the persistence context using the entity manager.

Persistence context is provided through the Java annotation @PersistenceContext in the javax.persistence package. The entity manager is provided through the Java class javax.persistence.EntityManager. In any managed bean, the EntityManager instance can be injected as shown below:

Example: Entity Manager Injection

@Stateless
public class UserBean {
    @PersistenceContext
    EntityManager entitymanager;
    ...
}

12.5.1. Application-Managed EntityManager

Application-managed entity managers provide direct access to the underlying persistence provider, org.hibernate.jpa.HibernatePersistenceProvider. The scope of the application-managed entity manager is from when the application creates it and lasts until the application closes it. You can use the @PersistenceUnit annotation to inject a persistence unit into the javax.persistence.EntityManagerFactory interface, which returns an application-managed entity manager.

Application-managed entity managers can be used when your application needs 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 instance creates a new, isolated persistence context. The EntityManager instance and its associated PersistenceContext is created and destroyed explicitly by your application. Application-managed entity managers can also be used when you cannot inject EntityManager instances directly, because the EntityManager instances are not thread-safe. EntityManagerFactory instances are thread-safe.

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

12.5.2. Container-Managed EntityManager

Container-managed entity managers manage the underlying persistence provider for the application. They can use the transaction-scoped persistence contexts or the extended persistence contexts. The container-managed entity manager creates instances of the underlying persistence provider as needed. Every time a new underlying persistence provider org.hibernate.jpa.HibernatePersistenceProvider instance is created, a new persistence context is also created.

12.6. Working with the EntityManager

When you have the persistence.xml file located in the /META-INF directory, the entity manager is loaded and has an active connection to the database. The EntityManager property can be used to bind the entity manager to JNDI and to add, update, remove and query entities.

Important

If you plan to use a security manager with Hibernate, be aware that Hibernate supports it only when EntityManagerFactory is bootstrapped by the JBoss EAP server. It is not supported when the EntityManagerFactory or SessionFactory is bootstrapped by the application. See Java Security Manager in How to Configure Server Security for more information about security managers.

12.6.1. Binding the EntityManager to JNDI

By default, JBoss EAP does not bind the EntityManagerFactory to JNDI. You can explicitly configure this in the persistence.xml file of your application by setting the jboss.entity.manager.factory.jndi.name property. The value of this property should be the JNDI name to which you want to bind the EntityManagerFactory.

You can also bind a container-managed transaction-scoped entity manager to JNDI by using the jboss.entity.manager.jndi.name property.

Example: Binding the EntityManager and the EntityManagerFactory to JNDI

<property name="jboss.entity.manager.jndi.name" value="java:/MyEntityManager"/>
<property name="jboss.entity.manager.factory.jndi.name" value="java:/MyEntityManagerFactory"/>

Example: Storing an Entity using the EntityManager

public User createUser(User user) {
    entityManager.persist(user);
    return user;
}

Example: Updating an Entity using the EntityManager

public void updateUser(User user) {
    entityManager.merge(user);
}

Example: Removing an Entity using the EntityManager

public void deleteUser(String user) {
    User user = findUser(username);
    if (user != null)
        entityManager.remove(user);
}

Example: Querying an Entity using the EntityManager

public User findUser(String username) {
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<User> criteria = builder.createQuery(User.class);
    Root<User> root = criteria.from(User.class);
    TypedQuery<User> query = entityManager
        .createQuery(criteria.select(root).where(
            builder.equal(root.<String> get("username"), username)));
    try {
        return query.getSingleResult();
    }
    catch (NoResultException e) {
        return null;
    }
}

12.7. Deploying the Persistence Unit

A persistence unit is a logical grouping that includes:

  • Configuration information for an entity manager factory and its entity managers.
  • Classes managed by the entity managers.
  • Mapping metadata specifying the mapping of the classes to the database.

The persistence.xml file contains persistence unit configuration, including the datasource name. The JAR file or the directory whose /META-INF/ directory contains the persistence.xml file is termed as the root of the persistence unit.

In Java EE environments, the root of the persistence unit must be one of the following:

  • An EJB-JAR file
  • The /WEB-INF/classes/ directory of a WAR file
  • A JAR file in the /WEB-INF/lib/ directory of a WAR file
  • A JAR file in the EAR library directory
  • An application client JAR file

Example: Persistence Settings File

<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 http://java.sun.com/xml/ns/persistence/persistence_2_2.xsd"
   version="2.2">
   <persistence-unit name="example" transaction-type="JTA">
      <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
      <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
      <mapping-file>ormap.xml</mapping-file>
      <jar-file>TestApp.jar</jar-file>
      <class>org.test.Test</class>
      <shared-cache-mode>NONE</shared-cache-mode>
      <validation-mode>CALLBACK</validation-mode>
      <properties>
         <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
         <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      </properties>
   </persistence-unit>
</persistence>

12.8. Second-level Caches

12.8.1. About Second-level Caches

A second-level cache is a local data store that holds information persisted outside the application session. The cache is managed by the persistence provider, improving runtime by keeping the data separate from the application.

JBoss EAP supports caching for the following purposes:

  • Web Session Clustering
  • Stateful Session Bean Clustering
  • SSO Clustering
  • Hibernate/JPA Second-level Cache
Warning

Each cache container defines a repl and a dist cache. These caches should not be used directly by user applications.

12.8.1.1. Default Second-level Cache Provider

Infinispan is the default second-level cache provider for JBoss EAP. Infinispan is a distributed in-memory key/value data store with optional schema, available under the Apache License 2.0.

12.8.1.1.1. Configuring a Second-level Cache in the Persistence Unit

You can use the shared-cache-mode element of the persistence unit to configure the second-level cache.

  1. See Create a Simple JPA Application to create the persistence.xml file in Red Hat CodeReady Studio.
  2. Add the following to the persistence.xml file:

    <persistence-unit name="...">
      (...) <!-- other configuration -->
      <shared-cache-mode>SHARED_CACHE_MODE</shared-cache-mode>
      <properties>
        <property name="hibernate.cache.use_second_level_cache" value="true" />
        <property name="hibernate.cache.use_query_cache" value="true" />
      </properties>
    </persistence-unit>

    The SHARED_CACHE_MODE element can take the following values:

    • ALL: All entities should be considered cacheable.
    • NONE: No entities should be considered cacheable.
    • ENABLE_SELECTIVE: Only entities marked as cacheable should be considered cacheable.
    • DISABLE_SELECTIVE: All entities except the ones explicitly marked as not cacheable should be considered cacheable.
    • UNSPECIFIED: Behavior is not defined. Provider-specific defaults are applicable.