Fork me on GitHub

Coherence Hibernate Second-Level Cache

This page describes how you can use Oracle Coherence as a second-level cache in Hibernate, an object-relational mapping library for Java applications. Since version 2.1 (released December 11th 2003) Hibernate has incorporated second-level caching, by allowing an implementation of a Service Provider Interface (SPI) to be configured. In Hibernate version 3.3 (released September 11th 2008) the second-level cache SPI was significantly redesigned. The Coherence Hibernate second-level cache described in this document implements the redesigned SPI used in Hibernate version 3.3 and later.

Using Coherence as a Hibernate second-level cache implementation allows multiple JVMs running the same Hibernate application to share a second-level cache. The use of Coherence caches in this scenario is completely controlled by Hibernate. You should have a good understanding of Hibernate second-level caching to successfully use the Coherence Hibernate second-level cache implementation. For more information on Hibernate second-level caching, see the "Improving Performance" chapter of the Hibernate Core Reference Manual at http://www.hibernate.org/docs.

Using Coherence as a Hibernate second-level cache implementation may be a good fit for Java applications that use Hibernate for data access and management, and that run in a cluster of application servers accessing the same database.

Installing the Coherence Hibernate Second-Level Cache

Installing the Coherence Hibernate second-level cache implementation amounts to obtaining a distribution of coherence-hibernate-second-level-cache-1.0.0.jar and making it available to JVM ClassLoaders. The easiest way to do so is to build and execute your Hibernate application with Maven, and add the following dependency to your application’s pom.xml:

<dependency>
    <groupId>com.oracle.coherence.hibernate</groupId>
    <artifactId>coherence-hibernate-second-level-cache</artifactId>
    <version>1.0.0</version>
</dependency>

Alternatively, you can download coherence-hibernate-second-level-cache-1.0.0.jar from a Maven repository (e.g. https://maven.java.net) and use it in JVM classpaths. Or you can build the Coherence Hibernate second-level cache implementation from sources.

Note that the Coherence Hibernate second-level cache implementation depends at runtime on an installation of Oracle Coherence, and an installation of Hibernate. These dependencies are most easily managed using Maven. You can install Coherence artifacts into your Maven repository as documented here: http://docs.oracle.com/middleware/1212/coherence/COHDG/gs_install.htm#A7113537.

Configuring Hibernate Second-Level and Query Caching

Hibernate uses three forms of caching: the session cache, the second-level cache, and the query cache.

The session cache caches entities within a Hibernate Session. A Hibernate Session is a transaction-level cache of persistent data, potentially spanning multiple database transactions, and typically scoped on a per-thread basis. As a non-clustered cache, the session cache is managed entirely by Hibernate.

The second-level and query caches span multiple transactions, and support the use of Coherence as a cache provider. The second-level cache is responsible for caching records across multiple Sessions (for primary key lookups). The query cache caches the result sets generated by Hibernate queries. Hibernate manages data in an internal representation in the second-level and query caches, meaning that these caches are usable only by Hibernate. For more information, see the "Improving Performance" chapter of the Hibernate Core Reference Manual at http://www.hibernate.org/docs.

To configure Coherence as the Hibernate second-level cache, set the hibernate.cache.region.factory_class property in Hibernate configuration to com.oracle.coherence.hibernate.cache.CoherenceRegionFactory. For example, include the following property setting in hibernate.cfg.xml:

<property name="hibernate.cache.region.factory_class">
    com.oracle.coherence.hibernate.cache.CoherenceRegionFactory
</property>

In addition to setting the hibernate.cache.region.factory_class property, you must also configure Hibernate to use second-level caching, and query caching if desired, by setting the appropriate Hibernate configuration properties to true, as follows:

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

Furthermore, you must configure each entity class mapped by Hibernate, and each Collection-typed field mapped by Hibernate, to use caching on a case-by-case basis. To configure mapped classes and Collection-typed fields to use second-level caching, add elements to the class’s mapping file as in the following example, or use the equivalent Hibernate annotations.

<hibernate-mapping package="org.hibernate.tutorial.domain">
    <class name="Person" table="PERSON">
        <cache usage="read-write" />
        <id name="id" column="PERSON_ID">
            <generator class="native"/>
        </id>
        <property name="age"/>
        <property name="firstname"/>
        <property name="lastname"/>
        <set name="events" table="PERSON_EVENT">
            <cache usage="read-write" />
            <key column="PERSON_ID"/>
            <many-to-many column="EVENT_ID" class="Event"/>
        </set>
        <set name="emailAddresses" table="PERSON_EMAIL_ADDR">
            <cache usage="read-write" />
            <key column="PERSON_ID"/>
            <element type="string" column="EMAIL_ADDR"/>
        </set>
    </class>
</hibernate-mapping>

The possible values for the usage attribute of the cache element are as follows:

<cache usage="transactional | read-write | nonstrict-read-write | read-only">

The meaning and effect of each possible value is documented below in the section on cache concurrency strategies.

To configure query caching, you must furthermore call setCacheable(), passing true, on each org.hibernate.Query executed by your application code, as in the following example:

public List listPersons() {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();
    Query query = session.createQuery("from Person");
    query.setCacheable(true);
    List result = query.list();
    session.getTransaction().commit();
    return result;
}

Finally, Hibernate provides the configuration property hibernate.cache.use_minimal_puts, which optimizes cache management for clustered caches by minimizing cache update operations. The Coherence caching provider enables this by default. Setting this property to false might increase overhead for cache management.

Types of Hibernate Second-Level Cache

Hibernate’s second-level cache design utilizes five different types of second-level cache, as reflected in the names of sub-interfaces of org.hibernate.cache.spi.Region:

  • EntityRegions cache the data of entity instances mapped by Hibernate. By default Hibernate uses the fully-qualified name of the entity class as the name of an EntityRegion cache; though the name can be overridden through configuration.
  • CollectionRegions cache the data of Collection-typed fields of mapped entities. Hibernate names CollectionRegion caches using the fully-qualified name of the entity class followed by the name of the Collection-typed field, separated by a period.
  • NaturalIdRegions cache mappings of secondary identifiers to primary identifiers for entities.
  • QueryResultsRegions cache the result sets of queries executed by Hibernate. Cache keys are formed using the query string and parameters, and cache values are collections of identifiers of entities satisfying the query. By default Hibernate uses one QueryResultsRegion with the name "org.hibernate.cache.internal.StandardQueryCache". Hibernate users can instantiate QueryResultsRegions by calling org.hibernate.Query.setCacheRegion() passing custom cache names (by convention these names should begin with "query.").
  • TimestampsRegions cache timestamps at which database tables were last written by Hibernate. These timestamps are used by Hibernate during query processing to determine whether cached query results can be used (if a query involves a certain table, and that table was written more recently than when the result set for that query was last cached, then the cached result set may be stale and cannot be used). Hibernate uses one TimestampsRegion named “org.hibernate.cache.spi.UpdateTimestampsCache”. The keys in this cache are database table names, and the values are machine clock readings.

EntityRegions, CollectionRegions, and NaturalIdRegions are treated by Hibernate as “transactional” cache regions, meaning that the full variety of cache concurrency strategies may be configured (see the next section). Whereas QueryResultsRegions and TimestampsRegions are used by Hibernate as “general data” regions, rendering cache concurrency strategies irrelevant for those types of caches.

Cache Concurrency Strategies

The Hibernate cache architecture defines four different "cache concurrency strategies" in association with its second-level cache. These are intended to allow Hibernate users to configure the degree of database consistency and transaction isolation desired for second-level cache contents, for data concurrently read and written through Hibernate. The following table describes the four Hibernate second-level cache concurrency strategies.

Strategy Intent Write Transaction Sequence
transactional Guarantee cache consistency with database, and repeatable read isolation, via JTA transactions enlisting both as resources. Cache and database committed atomically in same JTA transaction.
read/write Maintain strong consistency with database, and read committed isolation in second-level cache. Database committed first, then cache updated using locking model.
nonstrict read/write Better performance, but no guarantee of consistency with database or read committed isolation in second-level cache. Database committed first, then cache invalidated to cause subsequent read-through.
read only Best performance for read-only data. Not applicable.


For EntityRegions, CollectionRegions, and NaturalIdRegions, the appropriate cache concurrency strategy can be configured via the usage attribute of the cache element in the Hibernate mapping file for a mapped entity class, or via equivalent annotation.

The Coherence Hibernate second-level cache implementation does not support the transactional cache concurrency strategy.

Configuring Coherence Caches for Hibernate Second-Level Caching

By default, the Coherence Hibernate second-level cache implementation uses a cache configuration file named hibernate-second-level-cache-config.xml at the root level in coherence-hibernate-second-level-cache-1.0.0.jar. This configuration file defines cache mappings for Hibernate second-level caches. You can specify an alternative cache configuration file for Hibernate second-level caches using the Hibernate or Java property com.oracle.coherence.hibernate.cache.cache_config_file_path, whose value should be the path to a file or ClassLoader resource, or a file:// URL.

In fact it is recommended and expected that you specify an alternative cache configuration file customized for the domain model and consistency / isolation requirements of your particular Hibernate application. For each mapped entity class and Collection-typed field, it is recommended that you configure an explicit cache mapping to the scheme (with expiry and size parameters) appropriate for that cache given application requirements. See comments in the default cache configuration file for more detail on customizing cache configuration for your application - the default cache configuration file takes a conservative approach, and it is likely that you can optimize cache access latency and hit ratio (via size) for entity and Collection caches with relaxed consistency / isolation requirements.

In any case, it is recommended that you configure dedicated cache services for Hibernate second-level caches (as is done in the default cache configuration file), to avoid the potential for reentrant calls into cache services when Hibernate-based CacheStores are used. Furthermore, second-level caches should be size-limited in all tiers to avoid the possibility of heap exhaustion. Query caches in particular should be size-limited because the Hibernate API does not provide any means of controlling the query cache other than a complete eviction. Finally, expiration should be considered if the underlying database can be written by clients other than the Hibernate application.

Configuring Clients and Servers for Hibernate Second-Level Caching

Both the clients of the Coherence Hibernate second-level caches – e.g. application server JVMs running Hibernate-based applications – and the Coherence cache server JVMs actually holding the cache contents - need to have a common set of jar file artifacts available to their ClassLoaders. Specifically, both need coherence-hibernate-second-level-cache-1.0.0.jar and its dependencies Coherence and Hibernate (and their dependencies).

The Coherence cache server JVMs need the Hibernate core jar file to deserialize CacheEntry classes (org.hibernate.cache.spi.entry.*) since the Coherence Hibernate second-level cache implementation uses Coherence EntryProcessors to optimize concurrency control. However the cache server JVMs do not need the Hibernate application’s jar files containing entity classes etc.

The client / application server JVMs do of course need the Hibernate application’s jar files containing entity classes etc. And they should be configured to be “storage-disabled”, i.e. to not store contents of distributed caches. See comments in the default hibernate-second-level-cache-config.xml for details on how to accomplish that configuration – it amounts to starting clients and servers with slightly different cache configuration files, or passing –Dtangosol.coherence.distributed.localstorage=false to client JVMs.

Both client and server JVMs will need the same Coherence operational configuration (see http://docs.oracle.com/middleware/1212/coherence/COHDG/gs_config.htm#COHDG5002) specifying necessary cluster communication parameters. Coherence provides default operational configuration, but it is a best practice to override communication parameters and cluster name to make them unique for each separate application environment.