Apache Ignite Integrations

The Apache Ignite Integrations Developer Hub

Welcome to the Apache Ignite Integrations developer hub. You'll find comprehensive guides and documentation to help you start working with Apache Ignite Integrations as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    

Hibernate L2 Cache

Overview

Ignite In-Memory Data Fabric can be used as Hibernate Second-Level cache (or L2 cache), which can significantly speed-up the persistence layer of your application.

Hibernate is a well-known and widely used framework for Object-Relational Mapping (ORM). While interacting closely with an SQL database, it performs caching of retrieved data to minimize expensive database requests.

All work with Hibernate database-mapped objects is done within a session, usually bound to a worker thread or a Web session. By default, Hibernate only uses per-session (L1) cache, so, objects, cached in one session, are not seen in another. However, a global second-level (L2) cache may be used, in which the cached objects are seen for all sessions that use the same L2 cache configuration. This usually gives a significantly greater performance gain, because each newly-created session can take full advantage of the data already present in L2 cache memory (which outlives any session-local L1 cache).

While L1 cache is always enabled and fully implemented by Hibernate internally, L2 cache is optional and can have multiple pluggable implementaions. Ignite can be easily plugged-in as an L2 cache implementation, and can be used in all access modes (READ_ONLY, READ_WRITE, NONSTRICT_READ_WRITE, and TRANSACTIONAL), supporting a wide range of related features:

  • caching to memory and disk, as well as off-heap memory.
  • cache transactions, that make TRANSACTIONAL mode possible.
  • clustering, with 2 different replication modes: REPLICATED and PARTITIONED

To start using GridGain as a Hibernate L2 cache, you need to perform 3 simple steps:

  • Add Ignite libraries to your application's classpath.
  • Enable L2 cache and specify Ignite implementation class in L2 cache configuration.
  • Configure Ignite caches for L2 cache regions and start the embedded Ignite node (and, optionally, external Ignite nodes).

In the section below we cover these steps in more detail.

L2 Cache Configuration

To configure Ignite In-Memory Data Fabric as a Hibernate L2 cache, without any changes required to the existing Hibernate code, you need to:

  • Add dependency on hibernate-ignite module.
  • Configure Hibernate itself to use Ignite as L2 cache.
  • Configure Ignite cache appropriately.

Some of Hibernate classes that might be used by your application require a special BinaryTypeConfiguration to be set. For instance, the configuration has to be added for org.hibernate.cache.spi.CacheKey class in a way it's shown below:

BinaryConfiguration bCfg = new BinaryConfiguration();

// Setting specific binary configuration for a Hibernate class.
BinaryTypeConfiguration btCfg = new BinaryTypeConfiguration();

// Setting the class name.
btCfg.setTypeName(org.hibernate.cache.spi.CacheKey.class.getName());

// Setting special binary identity resolver.
btCfg.setIdentityResolver(new BinaryAbstractIdentityResolver() {
    @Override protected int hashCode0(BinaryObject obj) {
        return return obj.field("key").hashCode();
    }

    @Override protected boolean equals0(BinaryObject o1, BinaryObject o2) {
        Object obj0 = o1.field("key");
        Object obj1 = o2.field("key");

        return Objects.equals(obj0, obj1);
     }
});

// Applying the configuration.
bCfg.setTypeConfigurations(Collections.singleton(btCfg));

IgniteConfiguration igniteConfiguration = new IgniteConfiguration()
  .setBinaryConfiguration(bCfg);

Maven Configuration

Maven Dependency

In order to enable Ignite hibernate integration, you need to add ignite-hibernate dependency to your project, or when starting from command line, copy ignite-hibernate module from libs/optional to libs folder.

To add Ignite hibernate integration to your project, add the following dependency to your POM file:

<dependency>
  <groupId>org.apache.ignite</groupId>
  <artifactId>ignite-hibernate</artifactId>
  <version>RELEASE</version>
</dependency>

Hibernate Configuration Example

A typical Hibernate configuration for L2 cache with Ignite would look like the one below:

<hibernate-configuration>
    <session-factory>
        ...
        <!-- Enable L2 cache. -->
        <property name="cache.use_second_level_cache">true</property>
        
        <!-- Generate L2 cache statistics. -->
        <property name="generate_statistics">true</property>
        
        <!-- Specify Ignite as L2 cache provider. -->
        <property name="cache.region.factory_class">org.apache.ignite.cache.hibernate.HibernateRegionFactory</property>
        
        <!-- Specify the name of the grid, that will be used for second level caching. -->
        <property name="org.apache.ignite.hibernate.grid_name">hibernate-grid</property>
        
        <!-- Set default L2 cache access type. -->
        <property name="org.apache.ignite.hibernate.default_access_type">READ_ONLY</property>
        
        <!-- Specify the entity classes for mapping. -->
        <mapping class="com.mycompany.MyEntity1"/>
        <mapping class="com.mycompany.MyEntity2"/>
        
        <!-- Per-class L2 cache settings. -->
        <class-cache class="com.mycompany.MyEntity1" usage="read-only"/>
        <class-cache class="com.mycompany.MyEntity2" usage="read-only"/>
        <collection-cache collection="com.mycompany.MyEntity1.children" usage="read-only"/>
        ...
    </session-factory>
</hibernate-configuration>

Here, we do the following:

  • Enable L2 cache (and, optionally, the L2 cache statistics generation).
  • Specify Ignite as L2 cache implementation.
  • Specify the name of the caching grid (should correspond to the one in Ignite configuration).
  • Specify the entity classes and configure caching for each class (a corresponding cache region should be configured in Ignite).

Ignite Configuration Example

A typical Ignite configuration for Hibernate L2 caching looks like this:

<!-- Basic configuration for atomic cache. -->
<bean id="atomic-cache" class="org.apache.ignite.configuration.CacheConfiguration" abstract="true">
    <property name="cacheMode" value="PARTITIONED"/>
    <property name="atomicityMode" value="ATOMIC"/>
    <property name="writeSynchronizationMode" value="FULL_SYNC"/>
</bean>
 
<!-- Basic configuration for transactional cache. -->
<bean id="transactional-cache" class="org.apache.ignite.configuration.CacheConfiguration" abstract="true">
    <property name="cacheMode" value="PARTITIONED"/>
    <property name="atomicityMode" value="TRANSACTIONAL"/>
    <property name="writeSynchronizationMode" value="FULL_SYNC"/>
</bean>
 
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
    <!-- 
        Specify the name of the caching grid (should correspond to the 
        one in Hibernate configuration).
    -->
    <property name="gridName" value="hibernate-grid"/>
    ...
    <!-- 
        Specify cache configuration for each L2 cache region (which corresponds 
        to a full class name or a full association name).
    -->
    <property name="cacheConfiguration">
        <list>
            <!--
                Configurations for entity caches.
            -->
            <bean parent="transactional-cache">
                <property name="name" value="com.mycompany.MyEntity1"/>
            </bean>
            <bean parent="transactional-cache">
                <property name="name" value="com.mycompany.MyEntity2"/>
            </bean>
            <bean parent="transactional-cache">
                <property name="name" value="com.mycompany.MyEntity1.children"/>
            </bean>
 
            <!-- Configuration for update timestamps cache. -->
            <bean parent="atomic-cache">
                <property name="name" value="org.hibernate.cache.spi.UpdateTimestampsCache"/>
            </bean>
 
            <!-- Configuration for query result cache. -->
            <bean parent="atomic-cache">
                <property name="name" value="org.hibernate.cache.internal.StandardQueryCache"/>
            </bean>
        </list>
    </property>
    ...
</bean>

Here, we specify the cache configuration for each L2 cache region:

  • We use PARTITIONED cache to split the data between caching nodes. Another possible strategy is to enable REPLICATED mode, thus replicating a full dataset between all caching nodes. See Cache Distribution Models for more information.
  • We specify the cache name that corresponds an L2 cache region name (either a full class name or a full association name).
  • We use TRANSACTIONAL atomicity mode to take advantage of cache transactions.
  • We enable FULL_SYNC to be always fully synchronized with backup nodes.

Additionally, we specify a cache for update timestamps, which may be ATOMIC, for better performance.

Having configured Ignite caching node, we can start it from within our code the following way:

Ignition.start("my-config-folder/my-ignite-configuration.xml");

After the above line is executed, the internal Ignite node is started and is ready to cache the data. We can also start additional standalone nodes by running the following command from console:

$IGNITE_HOME/bin/ignite.sh my-config-folder/my-ignite-configuration.xml

For Windows, use the .bat script in the same folder.

The nodes may be started on other hosts as well, forming a distributed caching cluster. Be sure to specify the right network settings in GridGain configuration file for that.

Query Cache

In addition to L2 cache, Hibernate offers a query cache. This cache stores the results of queries (either HQL or Criteria) with a given set of parameters, so, when you repeat the query with the same parameter set, it hits the cache without going to the database.

Query cache may be useful if you have a number of queries, which may repeat with the same parameter values. Like in case of L2 cache, Hibernate relies on a 3-rd party cache implementation, and Ignite In-Memory Data Fabric can be used as such.

Consider using support for SQL-based In-Memory Queries in Ignite which should perform faster than going through Hibernate.

Query Cache Configuration

The configuration information above totally applies to query cache, but some additional configuration and code change is required.

Hibernate Configuration

To enable query cache in Hibernate, you only need one additional line in configuration file:

<!-- Enable query cache. -->
<property name="cache.use_query_cache">true</property>

Yet, a code modification is required: for each query that you want to cache, you should enable cacheable flag by calling setCacheable(true):

Session ses = ...;
 
// Create Criteria query.
Criteria criteria = ses.createCriteria(cls);
 
// Enable cacheable flag.
criteria.setCacheable(true);
 
...

After this is done, your query results will be cached.

Ignite Configuration

To enable Hibernate query caching in Ignite, you need to specify an additional cache configuration:


<property name="cacheConfiguration">
    <list>
        ...
        <!-- Query cache (refers to atomic cache defined in above example). -->
        <bean parent="atomic-cache">
            <property name="name" value="org.hibernate.cache.internal.StandardQueryCache"/>
        </bean>
    </list>
</property>

Notice that the cache is made ATOMIC for better performance.

Hibernate L2 Cache