| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| = Apache Ignite Hibernate L2 Cache |
| |
| == Overview |
| |
| Apache Ignite can be used as a http://hibernate.org[Hibernate, window=_blank] second-Level cache, |
| which can significantly speed-up the persistence layer of your application. |
| |
| 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, an 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). |
| |
| image::images/integrations/hibernate-l2-cache.png[Ignite Cluster] |
| |
| While the 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 with as a Hibernate L2 cache, without any changes required to the existing Hibernate code, you need to: |
| |
| * Add either `ignite-hibernate_5.3` or `ignite-hibernate_4.2` module as a dependency to your project depending on whether |
| Hibernate 5 or Hibernate 4 is used. Alternatively, you can copy JAR files of the same name from |
| `+{apache_ignite_relese}/libs/optional+` to `+{apache_ignite_relese}/libs+` folder if you start an Apache Ignite node |
| from a command line. |
| * Configure Hibernate itself to use Ignite as an L2 cache. |
| * Configure Ignite caches appropriately. |
| |
| === Maven Configuration |
| |
| To add Apache Ignite Hibernate integration to your project, add the following dependency to your pom.xml file: |
| |
| [tabs] |
| -- |
| tab:Hibernate 5[] |
| [source,xml] |
| ---- |
| <dependency> |
| <groupId>org.apache.ignite</groupId> |
| <artifactId>ignite-hibernate_5.3</artifactId> |
| <version>${ignite.version}</version> |
| </dependency> |
| ---- |
| tab:Hibernate 4[] |
| [source,xml] |
| ---- |
| <dependency> |
| <groupId>org.apache.ignite</groupId> |
| <artifactId>ignite-hibernate_4.2</artifactId> |
| <version>${ignite.version}</version> |
| </dependency> |
| ---- |
| -- |
| |
| === Hibernate Configuration Example |
| |
| A typical Hibernate configuration for L2 cache with Ignite would look like the one below: |
| |
| [tabs] |
| -- |
| tab:XML[] |
| [source,xml] |
| ---- |
| <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.ignite_instance_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: |
| |
| [tabs] |
| -- |
| tab:XML[] |
| [source,xml] |
| ---- |
| <!-- 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="igniteInstanceName" 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: |
| |
| [tabs] |
| -- |
| tab:Java[] |
| [source,java] |
| ---- |
| 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: |
| |
| [tabs] |
| -- |
| tab:Unix[] |
| [source,shell] |
| ---- |
| $IGNITE_HOME/bin/ignite.sh my-config-folder/my-ignite-configuration.xml |
| ---- |
| tab:Windows[] |
| [source,shell] |
| ---- |
| $IGNITE_HOME\bin\ignite.bat my-config-folder\my-ignite-configuration.xml |
| ---- |
| -- |
| |
| [NOTE] |
| ==== |
| 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 can be used as such. |
| |
| == 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: |
| |
| [tabs] |
| -- |
| tab:XML[] |
| [source,xml] |
| ---- |
| <!-- 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)`: |
| |
| [tabs] |
| -- |
| tab:Java[] |
| [source,java] |
| ---- |
| 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: |
| |
| [tabs] |
| -- |
| tab:XML[] |
| [source,xml] |
| ---- |
| <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> |
| ---- |
| -- |
| |
| == Example |
| |
| See a complete https://github.com/apache/ignite/blob/master/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/hibernate/HibernateL2CacheExample.java[example, window=_blank] |
| that is available on GitHub and in every Apache Ignite distribution. |