Coherence Hibernate CacheStore
This page describes how you can use Hibernate as the implementation of a Coherence CacheStore
.
Using Hibernate as the implementation of a Coherence CacheStore
may be a good fit for Java applications that use
Coherence APIs for data access and management, whose cache entries are objects or graphs appropriate for mapping
to relational tables via Hibernate, and that have simple transactional requirements (e.g. transactions affecting a
single cache entry at a time).
Installing the Coherence Hibernate CacheStore
Installing the Coherence Hibernate CacheStore implementation amounts to obtaining a distribution of
coherence-hibernate-cache-store-2.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-cache-store</artifactId>
<version>2.0.0</version>
</dependency>
Alternatively, you can download coherence-hibernate-cache-store-2.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
CacheStore implementation from sources.
Note that the Coherence Hibernate CacheStore 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.
Hibernate Configuration Requirements
Hibernate entities written and read via the HibernateCacheStore
module must use the assigned
ID generator
in Hibernate, and also have a defined ID property.
Disable the hibernate.hbm2ddl.auto
property in the hibernate.cfg.xml
file used by the HibernateCacheStore
module
to avoid excessive schema updates and possible deadlocks when starting a Coherence cluster with multiple storage members.
Configuring a HibernateCacheStore Constructor
The following examples illustrate how to configure a simple HibernateCacheStore
constructor, which accepts only an
entity name. This configures Hibernate by using the default configuration path, which looks for a hibernate.cfg.xml
file in the class path. You can also include a resource name or file specification for the hibernate.cfg.xml
file as
the second <init-param>
(set the <param-type>
element to java.lang.String
for a resource name and java.io.File
for a file specification). See the Javadoc for HibernateCacheStore
for more information.
The following example illustrates a simple coherence-cache-config.xml
file used to define a NamedCache cache object
named TableA
that caches instances of a Hibernate entity (com.company.TableA
). To define more entity caches, add
additional <cache-mapping>
elements.
<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<caching-scheme-mapping>
<cache-mapping>
<cache-name>TableA</cache-name>
<scheme-name>distributed-hibernate</scheme-name>
<init-params>
<init-param>
<param-name>entityname</param-name>
<param-value>com.company.TableA</param-value>
</init-param>
</init-params>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<distributed-scheme>
<scheme-name>distributed-hibernate</scheme-name>
<backing-map-scheme>
<read-write-backing-map-scheme>
<internal-cache-scheme>
<local-scheme></local-scheme>
</internal-cache-scheme>
<cachestore-scheme>
<class-scheme>
<class-name>
com.tangosol.coherence.hibernate.HibernateCacheStore
</class-name>
<init-params>
<init-param>
<param-type>java.lang.String</param-type>
<param-value>{entityname}</param-value>
</init-param>
</init-params>
</class-scheme>
</cachestore-scheme>
</read-write-backing-map-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
</caching-schemes>
</cache-config>
The next example illustrates that you can also use the predefined {cache-name}
macro to eliminate the need for the
<init-params>
portion of the cache mapping.
<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<caching-scheme-mapping>
<cache-mapping>
<cache-name>TableA</cache-name>
<scheme-name>distributed-hibernate</scheme-name>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<distributed-scheme>
<scheme-name>distributed-hibernate</scheme-name>
<backing-map-scheme>
<read-write-backing-map-scheme>
<internal-cache-scheme>
<local-scheme></local-scheme>
</internal-cache-scheme>
<cachestore-scheme>
<class-scheme>
<class-name>
com.tangosol.coherence.hibernate.HibernateCacheStore
</class-name>
<init-params>
<init-param>
<param-type>java.lang.String</param-type>
<param-value>com.company.{cache-name}</param-value>
</init-param>
</init-params>
</class-scheme>
</cachestore-scheme>
</read-write-backing-map-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
</caching-schemes>
</cache-config>
The final example illustrates that, if naming conventions allow, the mapping can be completely generalized to enable a cache mapping for any qualified class name (entity name).
<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<caching-scheme-mapping>
<cache-mapping>
<cache-name>com.company.*</cache-name>
<scheme-name>distributed-hibernate</scheme-name>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<distributed-scheme>
<scheme-name>distributed-hibernate</scheme-name>
<backing-map-scheme>
<read-write-backing-map-scheme>
<internal-cache-scheme>
<local-scheme></local-scheme>
</internal-cache-scheme>
<cachestore-scheme>
<class-scheme>
<class-name>
com.tangosol.coherence.hibernate.HibernateCacheStore
</class-name>
<init-params>
<init-param>
<param-type>java.lang.String</param-type>
<param-value>{cache-name}</param-value>
</init-param>
</init-params>
</class-scheme>
</cachestore-scheme>
</read-write-backing-map-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
</caching-schemes>
</cache-config>
Creating a Custom Hibernate-Based CacheStore
While the provided HibernateCacheStore
module provides a solution for most entity-based caches, there may be cases where
an application-specific, Hibernate-based CacheStore
module is necessary. For example, for providing parameterized queries,
or including or post-processing query results.
Care must be taken in this scenario to avoid causing re-entrant calls into Coherence cache services, which could be
possible (depending on service names) if Hibernate is also configured to use the Coherence-based second-level cache
implementation. Therefore, all methods in a custom Hibernate-based CacheLoader
or CacheStore
implementation should
be careful to call the Hibernate Session.setCacheMode(CacheMode.IGNORE)
method to disable cache access. Better yet,
the Hibernate configuration used by the custom Hibernate-based CacheStore
should disable second-level caching.
In some cases, you may want to extend the provided HibernateCacheStore
with application-specific functionality.
The most obvious reason for this is to take advantage of a preexisting, programmatically configured SessionFactory
instance. But note that it is possible to inject a pre-configured SessionFactory
instance into the provided
HibernateCacheStore
via Spring integration.
JDBC Isolation Level
In cases where all access to a database is through Coherence, cache store modules naturally enforce ANSI-style repeatable read isolation as read operations, and write operations are executed serially on a per-key basis (by using the Partitioned Cache Service). Increasing database isolation above the repeatable read level does not yield increased isolation because cache store operations might span multiple partitioned cache nodes (and thus multiple database transactions). Using database isolation levels below the repeatable read level does not result in unexpected anomalies, and might reduce processing load on the database server.
Fault-Tolerance for Hibernate Cache Store Operations
For single-cache-entry updates, cache store operations are fully fault-tolerant in that the cache and database are guaranteed to be consistent during any server failure (including failures during partial updates). While the mechanisms for fault-tolerance vary, this is true for both write-through and write-behind caches.
Coherence does not support two-phase cache store operations across multiple cache store instances. In other words, if two cache entries are updated, triggering calls to cache store modules sitting on separate servers, it is possible for one database update to succeed and for the other to fail. In this case, you might want to use a cache-aside architecture (updating the cache and database as two separate components of a single transaction) with the application server transaction manager. In many cases, it is possible to design the database schema to prevent logical commit failures (but obviously not server failures). Write-behind caching avoids this issue because put operations are not affected by database behavior (and the underlying issues have been addressed earlier in the design process).
Using Fully Cached Data Sets
There are two scenarios where using fully cached data sets would be advantageous. One is when you are performing distributed queries on the cache; the other is when you want to provide continued application processing despite a database failure.
Distributed queries offer the potential for lower latency, higher throughput, and less database server load, as opposed to executing queries on the database server. For set-oriented queries, the data set must be entirely cached to produce correct query results. More precisely, for a query issued against the cache to produce correct results, the query must not depend on any uncached data.
Distributed queries enable you to create hybrid caches. For example, it is possible to combine two uses of NamedCache: a fully cached size-limited data set for querying (for example, the data for the most recent week), and a partially cached historical data set used for singleton read operations. This approach avoids data duplication and minimizes memory usage.
While fully cached data sets are usually bulk-loaded during application startup (or on a periodic basis), cache store integration can be used to ensure that both cache and database are kept fully synchronized.
Another reason for using fully cached data sets is to provide the ability to continue application processing even if the underlying database fails. Using write-behind caching extends this mode of operation to support full read-write applications. With write-behind, the cache becomes (in effect) the temporary system of record. Should the database fail, updates are queued in Coherence until the connection is restored. At this point, all cache changes are sent to the database.
API for HibernateCacheStore and HibernateCacheLoader
The Oracle Coherence Hibernate Integration project includes a default entity-based CacheStore
implementation,
HibernateCacheStore
, and a corresponding CacheLoader
implementation, HibernateCacheLoader
, in the
com.oracle.coherence.hibernate.cachestore
package.
The following table describes the different constructors for the HibernateCacheStore
and HibernateCacheLoader
classes. For more detailed technical information, see the Javadoc for these classes.
Constructor | Description |
---|---|
HibernateCacheLoader() and HibernateCacheStore() | These constructors are the default constructors for creating a new instance of a cache loader or cache store. They do not create a Hibernate SessionFactory object. To inject a Hibernate SessionFactory object after you use these constructors, call the setSessionFactory() method. |
HibernateCacheLoader(java.lang.String entityName) and HibernateCacheStore(java.lang.String entityName) | These constructors create a Hibernate SessionFactory object using the default Hibernate configuration (hibernate.cfg.xml) in the classpath. |
HibernateCacheStore(java.lang.String entityName, java.lang.String sResource) and HibernateCacheStore(java.lang.String entityName, java.lang.String sResource) | These constructors create a Hibernate SessionFactory object based on the configuration file provided (sResource). |
HibernateCacheLoader(java.lang.String entityName, java.io.File configurationFile) and HibernateCacheStore(java.lang.String entityName, java.io.File configurationFile) | These constructors create a Hibernate SessionFactory object based on the configuration file provided (configurationFile). |
HibernateCacheStore(java.lang.String entityName, org.hibernate.SessionFactory sFactory) and HibernateCacheStore(java.lang.String entityName, org.hibernate.SessionFactory sFactory) | These constructors accept an entity name name and a Hibernate SessionFactory. |