JPA 2.0 Cache Vs. Hibernate Cache: Differences in Approach

Friday Jul 9th 2010 by Sangeetha S

Learn the differences between the caching approaches and capabilities of JPA 2.0 and Hibernate.

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.

Figure 1. JPA Level 1 (L1) 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.

Figure 2. JPA Level 2 (L2) 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.

Pros, Cons and Best Uses of JPA Level 2 Cache

Here are the pros and cons of JPA Level 2 cache:

  • Pros:
    • Avoids database access for already loaded entities
    • Faster for reading frequently accessed unmodified entities
  • Cons:
    • Memory consumption for large amount of objects
    • Stale data for updated objects
    • Concurrency for write (optimistic lock exception or pessimistic lock)
    • Bad scalability for frequent or concurrently updated entities

Level 2 cache is best used for entities that are frequently read, infrequently modified, and not critical if stale. You can use the query cache technique to cache queries that are executed often with the same parameters for tables that are rarely modified.

Caching in Hibernate

Hibernate also maintains two levels of cache: first-level and second-level cache. The first-level cache is responsible for storing the results within a particular session instance, while the second-level cache is associated with the SessionFactory instance.

Hibernate uses first-level cache by default to store the objects for every transaction. Hibernate's second-level cache, which is supported by the SessionFactory, enables the objects to be accessed at the application level, thereby reducing the number of database transactions required for accessing an object. Hibernate achieves caching by storing the individual property values of the instance rather than storing the objects themselves.

Hibernate 3.0 supports the following four open source caching implementations for second-level cache:

  • EHCache (org.hibernate.cache.EhCacheProvider) -- Default
  • OSCache (org.hibernate.cache.OSCacheProvider)
  • SwarmCache (org.hibernate.cache.SwarmCacheProvider)
  • JBoss TreeCache (org.hibernate.cache.TreeCacheProvider)

The second-level cache can be enabled or disabled by setting the property hibernate.cache.use_second_level_cache to true (the default for classes that specify <cache> mapping) or false, respectively. Here is a true setting:

<property name="hibernate.cache.use_second_level_cache">true</property>

You can choose which implementation to use for an application by setting the hibernate.cache.provider_class property in the hibernate.cfg.xml file as follows.

<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

You also can enable caching at the class level or the collection level by setting the <cache> element in the mapping file as follows:

<cache usage="read-only" region="regionName" include="all"/>

Here's a breakdown of the elements in the above code:

  • Usage specifies the caching strategy and can take other values such as transactional, read-write and nonstrict-read-write.
  • Region is an optional attribute that specifies the second-level cache region. By default it is the name of the class/collection.
  • Include is an optional attribute that takes the all value by default. If the value non-lazy is set to include then entities having lazy=true cannot be cached.

You can also enable caching by setting the <class-cache> and <collection-cache> elements in the hibernate.cfg.xml file, after which you would configure the cache rule for classes for which you want cache to be enabled in a separate EhCache configuration file (ehcache.xml) and place it in the root directory of the project.

You can also cache queries that are executed very frequently with the same set of parameters by using query cache. Query cache is set to false by default and you can enable it by adding the following property in the hibernate.cfg.xml file:

<property name="hibernate.cache.use_query_cache">true</property>

This query adds StandardQueryCache and UpdateTimestampsCache regions, which hold the query cached results and the time stamps of the most recent update to the table, respectively. The query results can be cached for a particular query by calling setCacheable(true) on the query instance.

Hibernate 3.5 Caching

The Hibernate caching strategies remain the same in version 3.5, but certain additional cache providers such as JBoss Cache 2, JBoss Cache 1.x (part of Hibernate 3.2) and Hashtable (not for production) have been added.

The other major advancement in Hibernate 3.5 is the addition of Infinispan as another standard for second-level cache. Infinispan is an open source, scalable data grid platform that exposes a JCache (JSR-107)-compatible cache interface. Infinispan provides a much higher degree of concurrency because it uses a specialized data structure, provides a massive heap capability and is not tied just to Java. It also supports PHP, Python, Ruby etc.


In this article we compared caching in JPA 2.0 with the caching in Hibernate. By introducing new caching features and promoting standardization, JPA 2.0 has made many tasks easier for developers. However, Hibernate is far ahead in many aspects because all its features have been supported for much longer.


The authors would like to sincerely thank Mr. Subrahmanya SV (VP, ECOM Research Group, E&R) for his ideas, guidance, support and constant encouragement and Ms. Mahalakshmi for kindly reviewing this article and providing valuable comments.

About the Authors

Sangeetha S. works as a Senior Technical Architect at the E-Commerce Research Labs at Infosys Technologies. She has over 10 years of experience in design and development of Java and Java EE applications. She has co-authored a book on 'J2EE Architecture' and also has written articles for online Java publications.

Nitin KL works at the E-Commerce Research Labs at Infosys Technologies. He is involved in design and development of Java EE applications using Hibernate, iBATIS, and JPA.

Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved