March 1, 2021
Hot Topics:

JPA 2.0 Cache Vs. Hibernate Cache: Differences in Approach

  • By Sangeetha S, Nitin KL
  • Send Email »
  • More Articles »

Hibernate and the Java Persistence API (JPA) are two leading technologies for managing the persistence and object relational mapping (ORM) of Java EE and Java SE applications. Hibernate's open source, lightweight and transparent framework simplified ORM by mapping database tables to persistent classes in XML files and generating the SQL script at runtime. JPA then made XML-based ORM much simpler by replacing the traditional XML mapping files with metadata annotation, enabling developers to persist the state of their Java applications to relational databases through metadata.

JPA 2.0 (JSR 317), the latest version released in November 2009, improved on the 1.0 version's basic features by upgrading the domain modeling, ORM capabilities, entity manager features, query interfaces and Java Persistence Query Language (JPQL). The JPA 2.0 specification also introduced new APIs for criteria queries, caching, locking, as well as a metamodel API and support for validation.

Hibernate itself implemented JPA through the Hibernate Annotations and Hibernate EntityManager libraries (or flavors), which are built on top of the Hibernate Core libraries. Hibernate EntityManager is a complete implementation of JPA and it follows the JPA lifecycle, while Hibernate Annotations has certain annotations specific to Hibernate (apart from the standard ones that are part of JPA) and it follows the Hibernate lifecycle. Hibernate 3.5 (released in March 2010) has complete support for JPA 2, with Hibernate 3.5 Hibernate Annotations, Hibernate EntityManager and Hibernate Envers all integrated as part of the core project.

So what makes these two ORM technologies that seem to have so much in common different? In this article, we will present a brief comparison of JPA 2.0 and Hibernate with respect to their caching approaches and capabilities.

Caching in JPA 2

Caching is essential to optimizing an application's performance and database access. By storing the data needed to serve requests, caching reduces the time required to access an object from the database. JPA 2.0 supports two levels of caching, JPA Level 1 (L1) Cache and JPA Level 2 (L2) Cache.

JPA Level 1 Cache

A JPA entity manager uses persistence context to manage entities. The persistence context associated with the respective entity managers acts as the first-level cache. At any point within a persistence context, an entity manager will have only one instance of the object mapped to a particular row in the database. When another user in a different persistence context refers to the same entity object, JPA uses the scope of the persistence context to resolve the situation.

The persistence context can be in either transaction scope (the default) or extended scope. In transaction scope, when a user conversation spans across multiple persistence contexts, the entities get detached at the end of the transaction. To persist the changes on a detached entity in a different persistence context, the merge() operation is used on the entity manager.

Here is an example of transaction scope:

@Statelesspublic EmpDetailsBean implements EmpDetails {@PersistenceContextEntityManager entityManager;public Employee addEmployee(String empId, String empName, String empUni) {Employee employee = new Employee(empId, empName, empUnit);entityManager.persist(employee); //employee is managed entityreturn employee; //employee is detached entity}public Employee updateEmployee(Employee employee) {//employee is detached entity, employee1 is managed entityEmployee employee1 = entityManager.merge(employee);return employee;}}

In extended scope, the persistence context spans across multiple transactions, so the set of entities are not detached; they remain managed. Extended scope is better suited for applications where in a user spans multiple requests.

Here is an example of extended scope:

@Statefulpublic EmpDetailsBean implements EmpDetails {@PersistenceContext(type=PersistenceContextType.EXTENDED)EntityManager entityManager;//Cached employeeprivate Employee employee;public void addEmployee(String empId, String empName, String empUnit) {employee = new Employee(empId, empName, empUnit);entityManager.persist(employee); //employee is managed entity}public void updateEmployee(String empUnit) {employee.setUnit(empUnit); //employee is managed entity}}

However, the usage of extended scope should be reviewed thoroughly with regards to memory consumption for cached entity objects; users should weigh the consequences of cached entities being updated by another transaction against the benefits of caching. The choice depends entirely on the application and the number of concurrent transactions involved in it, coming down to whether or not it performs better than a direct database read. Figure 1 shows a diagram of JPA level 1 cache.

JPA Level 2 Cache

Level 2 cache was introduced in the JPA 2.0 release. JPA provides a Cache API for basic cache operations, while level 2 cache shares the state of an entity -- which is accessed with the help of the entity manager factory -- across various persistence contexts. Level 2 cache underlies the persistence context, which is highly transparent to the application. Figure 2 shows a diagram of JPA level 2 cache.

Level 2 cache is used typically to increase performance. However, using cache may lead to "stale" data, so you may choose to disable caching. To enable or disable caching on a class, you can use the @Cacheable annotation.

public interface Cache {/*** Whether the cache contains data for the given entity.*/public boolean contains(Class cls, Object primaryKey);/*** Remove the data for the given entity from the cache.*/public void evict(Class cls, Object primaryKey);/*** Remove the data for entities of the specified class (and its* subclasses) from the cache.*/public void evict(Class cls);/*** Clear the cache.*/public void evictAll();}

The Cache API provided by JPA 2.0 also allows you to refresh or bypass caching by using query hints, which are defined with two enums: CacheRetrieveMode and CacheStoreMode. You use CacheRetrieveMode to read entity data from the cache (the default) by specifying this enum when the data is retrieved as follows:

javax.persistence.cache.retrieveMode: CacheRetrieveMode

To bypass the cache, you would get data directly from the database.

You use CacheStoreMode to insert/update entity data into cache when the data is read from a database and committed into a database (the default) by specifying when the data is committed to the database as follows:

javax.persistence.cache.storeMode: CacheStoreMode

CacheStoreMode does not force a refresh of already cached items when reading from the database.

To bypass the cache, don't insert into cache. To refresh the cache, insert/update entity data into cache when the data is read from the database and committed into the database. This will force a refresh of cache for items read from database.

When Level 2 cache is enabled, the persistence provider will look for the entities in the persistence context first. If it does not find them there, the persistence provider will look in the Level 2 cache next instead of sending a query to the database.

Page 1 of 2

This article was originally published on July 10, 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