Coherence Hibernate Second-Level Cache
This page describes how you can use Oracle Coherence
as a second-level cache in Hibernate ORM, 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. Over
the next couple of versions the SPI was further refined leading to breaking changes.
Therefore, we provide dedicated releases of the Hibernate Second-Level Cache implementations for Oracle Coherence depending on the Hibernate versions. The following versions are support:
Module Name | Supported Hibernate Versions |
---|---|
coherence-hibernate-cache-4 | 4.3.x |
coherence-hibernate-cache-5 | 5.0.x and 5.1.x |
coherence-hibernate-cache-52 | 5.2.x |
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 relevant chapter in 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.
NOTE: Before you use the Coherence Hibernate Cache support, please also consider other caching strategies. Ultimately, you should make a decision that is most applicable to the needs of your application.
Installing the Coherence Hibernate Second-Level Cache
Installing the Coherence Hibernate second-level cache implementation amounts to
obtaining a distribution of coherence-hibernate-cache-xx-2.0.0.jar
for the respective Hibernate version of your application.
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-cache-xx</artifactId>
<version>2.0.0</version>
</dependency>
Alternatively, you can download coherence-hibernate-cache-xx-2.0.0.jar
from a Maven repository (e.g. https://repo1.maven.org/maven2/) 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 by default on Coherence CE (Community Edition).
Configuring Hibernate Second-Level and Query Caching
Hibernate uses three forms of caching:
- Session cache
- Second-level cache
- 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 chapter on Caching of the 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 <cache>
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 anEntityRegion
cache; though the name can be overridden through configuration.CollectionRegions
cache the data of Collection-typed fields of mapped entities. Hibernate namesCollectionRegion
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 oneQueryResultsRegion
with the name "org.hibernate.cache.internal.StandardQueryCache
". Hibernate users can instantiateQueryResultsRegions
by callingorg.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 oneTimestampsRegion
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-cache-xx-2.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-cache-xx-2.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.