February 28, 2021
Hot Topics:

The JPA 2 Enhancements Every Java Developer Should Know

  • By KL Nitin
  • Send Email »
  • More Articles »

The Java Persistence API version 2 (JPA 2), released as part of the Java EE 6 specification in November 2009, introduced new and interesting features to the Java community. In this article, I examine some of the major advancements that JPA 2 made in its API, the Java Persistence Query Language (JPQL), and the properties defined in its persistence.xml configuration file. The code snippets provided are all compatible with EclipseLink, which is the reference implementation of JPA 2.

JPA 2 API Enhancements

In this section, I describe the new API methods added to the JPA API in version 2. Specifically, I discuss the enhancements made to the following APIs:

  • EntityManager
  • EntityManagerFactory
  • Query

Enhancements in EntityManagerFactory Interface

EntityManagerFactory acts as a pool of EntityManager instances, which are used to interact with the database. EntityManagerFactory is created for each database and it is analogous to a connection pool. The EntityManagerFactory instance is created using the createEntityManagerFactory static method of the Persistence class with the argument being the persistence unit name, for example:

EntityManagerFactory emf = 

JPA 2 also introduced a second layer of cache, which is shared across various persistence contexts and can be accessed using the EntityManagerFactory. (For more details refer to JPA 2.0 Cache Vs. Hibernate Cache: Differences in Approach.) The Cache interface introduced in JPA 2 can be implemented to provide this second-level cache. An instance of Cache can be obtained by invoking thegetCache() method on the EntityManagerFactory instance, which can then be used to interact with the second-level cache.

Here is an example:

EntityManagerFactory emf = 
Cache cache = emf.getCache();

Enhancements in EntityManager Interface

Entities are the basic programming artifact used in JPA programming; they are used to provide object relational mapping (ORM) using various metadata annotations. These entity instances are managed by the EntityManager instance, which is obtained from EntityManagerFactory. All the operations on the Entity instances are managed by EntityManager, much like a connection instance.

The EntityManager instance is obtained in the following way from the EntityManagerFactory:

EntityManagerFactory emf = 
EntityManager em = emf.createEntityManager();

The additional methods included in the EntityManager interface are:

  • detach
  • getEntityManagerFactory
  • Overloaded find methods

1. detach

The detach method defined in JPA 2 removes the specified entity from the persistence context and removes the changes made to the entity before flushing is all undone. JPA 1.x defined only a single clear method for removing all the managed entities from the persistence context. While this method was very useful for clearing the persistence context, it had its own limitation: The developer was not allowed to remove a specific instance from the persistence context. This is now possible in JPA 2 using the new detach method, which can be used as follows:

Item myItem = new Item(); 

In the above example a call to persist on the detached myItem instance will not have any effect, because it will be removed from the database when the detach is invoked and hence will not be stored.

2. getEntityManagerFactory

The getEntityManagerFactory method is used to obtain the EntityManagerFactory object, which is responsible for creating the EntityManager instances that are used to manage the entities. Here's an example:

   EntityManagerFactory entityMgrFactory = em.getEntityManagerFactory();

3. Overloaded find

The find method is used to retrieve a specific entity from the persistence context based on its primary key. JPA 2 introduces three overloaded find methods. The first overloaded method searches for an entity with respect to its primary key and then locks the entity with its respective lock type specified in the method. A lock is generally put on an entity to prevent any another transaction from updating the entity when the present transaction is modifying it.

Pessimistic and optimistic locking are the two main locking modes. (Refer to Pessimistic Locking in JPA 2 and Hibernate for more details on the locking modes in JPA. Here's an example:

   Item myItem = em.find(Item.class, 1, LockModeType.PESSIMISTIC_READ);

In general, the effect of the find method with a lock type is equivalent to searching for the entity type and then applying a lock mode to it. But if the lock mode specified is pessimistic with a version attribute set to the entity, an optimistic version check is performed to obtain the lock. If these checks fail, then an OptimisticLockException is thrown. If a failure in the database-locking mechanism causes the transaction to be rolled back, then a PessimisticLockException is thrown. Alternatively, if a statement-level rollback happens, then a LockTimeoutException is thrown by the persistence provider.

The second overloaded find method searches for an entity based on the primary key, using a vendor-specific property that is supplied to it as a Map object. If this property is not recognized, then it is not considered for finding the entity. Here's an example:

Item myItem = em.find(Item.class, 1, vendorSpecificMap);

The third overloaded find method uses the primary key and vendor-specific properties and applies a lock on the entity. Here's an example:

Item myItem = em.find(Item.class, 1, vendorSpecificMap, LockModeType.PESSIMISTIC_READ);

Enhancements in Query Interface

The Query interface is used to execute JPQL queries in JPA. It is obtained in the following way:

EntityManagerFactory emf = 
EntityManager em = emf.createEntityManager();
Query myQuery = em.createNamedQuery("Item.findAll");

The additional methods included in the Query interface as part of JPA 2 are:

  • setLockMode and getLockMode
  • getHints
  • getMaxResults
  • getFirstResult
  • getFlushMode

1. setLockMode and getLockMode

The setLockMode method is used to obtain a lock on the object returned as a result of the query. In general, the lock is obtained on individual entities affected by that query. Here's an example:

   Query myQuery = em.createNamedQuery("Item.findAll") ; 

The getLockMode method is used to obtain the actual lock applied to the Query instance. Here's an example:

Query myQuery = em.createNamedQuery("Item.findAll") ;   
LockModeType lockMode = myQuery.getLockMode();

2. getHints

The setHint method (introduced as part of JPA 1) adds a vendor-specific hint to the query; these hints are not portable across different vendors. The getHints method defined as part of JPA 2 allows the developer to obtain the previously set hints to the query instance. Here's an example:

   Query myQuery = em.createNamedQuery("Item.findAll"); 
myQuery.setHint("eclipselink.cache-usage", "DoNotCheckCache");
Map<String, Object> myMap = myQuery.getHints();

These hints can also be provided when the named query is created in the following manner:

@NamedQuery(name = "Item.findAll", query = "SELECT i FROM Item i", hints={@QueryHint(name="eclipselink.cache-usage",



3. getMaxResults

This method returns the maximum number of results that a query instance is supposed to return. If this value is not set using setMaxResults (part of JPA 1) to the query object, then the result of this method would be equivalent to Integer.MAX_VALUE. Here's an example:

   Query myQuery = em.createNamedQuery("Item.findAll"); 
System.out.println("GET MAX RESULT " + myQuery.getMaxResults());

4. getFirstResult

The setFirstResult (part of JPA1) method of the Query interface sets the position of the first record that needs to be obtained from the Query object. This value can now be retrieved using the getFirstResult method. If the position value is not set, it returns 0. Here's an example:

   Query myQuery = em.createNamedQuery("Item.findAll") ; 
System.out.println("FIRST RESULT " + myQuery.getFirstResult());

5. getFlushMode

Flush modes are important for ensuring the integrity of the data obtained through queries. AUTO and COMMIT are the two FlushModeTypes available. If the flush mode is set to AUTO (the default mode), then the persistence provider has to ensure that the result of the query is consistent with the operations performed on the entities. This is ensured by updating the state of the entity after each transaction so that the other transactions do not get any inconsistent data.

On the other hand, if the flush mode is COMMIT, then the persistence provider does not take the responsibility of committing the transaction. Instead, it synchronizes the data once the database COMMIT is performed. The getFlushMode method returns the FlushModeTypes set to the query instance and returns the flush mode set at the EntityManager level if it is not set. Here's an example:

   Query myQuery = em.createNamedQuery("Item.findAll") ; 
FlushModeType flushMode = myQuery.getFlushMode();

Originally published on https://www.developer.com.

Page 1 of 2

This article was originally published on October 27, 2010

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date