blog.broncotoxique.com

Juste another geek’s website

How to: Spring-Boot 2.x.x Hibernate 5.x.x EhCache 3.x.x

This post is the very short sumup of how to setup and run Hibernate L2 Cache, with EhCache 3. A version of the full documentation is here Hibernate 5.6 – Cache

Since Spring-boot 2.x.x use EhCache 3.x.x to serve the caching features of Spring, and Hibernate 5.x.x use EhCache 2.x.x as cache engine to provide it’s L2 cache feature, here you’ll how to use EhCache 3 with Hibernate. Thuth you’ll have only one cache running into your backend.

First of all, why use L2 cache ? It used mostly for reduce response time of the persistance layer of your code, and reduce database load.

The way it work is “pretty simple”. Spring maintainers provide JPA + Hibernate has persistence, through ORM, solution, the Hibernate bootstrap is pre-wired into Spring-Boot plus an entry that allow to send some Hibernate specific configuration values directly to hibernate. We will use this entry to sent the cache config options.

So now, how to make Hibernate use EhCache 3 as L2 cache engine. Since Spring chossed EhCache 3 to do their own cache system, I choesed to use EhCache 3 for Hibernate L2. keep in mind that if you use the Spring Cache module you’ll have to think carefully the usage of you cache because Spring and Hibernate might share the same cache instance at runtime.

In order to add make it work, you’ll have to:

1 – Add the following dependencies to your project, I let you adapt if you use another dependencies manager than Maven

<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jcache</artifactId>
</dependency>

The versions I used are the following. hibernate-jcache v5.6.10Final, witch will make the bridge from Hibernate and EHCache by implementing the new Javax Cache JSR-107. cache-api v1.1.1, witch is the Javax Cache JSR-107 Api. ehcache v3.10.0, witch implement Javax Cache API.

All the version are provide by Spring Boot Starter Parent, unless you want to override them.

2 – Configure the cache using Spring configuration system

spring:
jpa:
properties:
javax:
persistence:
sharedCache:
#required - enable selective caching mode - only entities with @Cacheable annotation will use L2 cache.
mode: ENABLE_SELECTIVE
hibernate:
#optional - enable SQL statements formatting.
format_sql: false
#optional - generate statistics to check if L2/query cache is actually being used.
generate_statistics: true
cache:
#required - turn on L2 cache.
use_second_level_cache: true
#optional - turn on query cache.
use_query_cache: true
# query_cache_factory: org.hibernate.cache.spi.StandardTimestampsCacheFactory
region_prefix: hibernate_l2
#use_reference_entries: true
#default_cache_concurrency_strategy: read-write
region:
#required - classpath to cache region factory.
factory_class: jcache
ehcache:
missing_cache_strategy: create-warn
javax:
cache:
provider: org.ehcache.jsr107.EhcacheCachingProvider
uri: classpath:ehcache.xml
missing_cache_strategy: create-warn

logging:
level:
org:
hibernate:
cache: error

3 – Cache configuration

Since Hibernate is manging the cache creation, we provide a cache default configuration that will be used at eache cache creation done by Hibernate. The config file should be into your resources dir, and named ehcache.xml.

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.ehcache.org/v3"
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">

<service>
<jsr107:defaults default-template="default" enable-statistics="true" enable-management="false" />
</service>

<persistence directory="./../temp/ehcache/cache" />

<!-- Mandatory Default Cache configuration. These settings will be applied
to caches created programmatically using CacheManager.add(String cacheName). -->
<cache-template name="default">
<expiry>
<ttl unit="seconds">600</ttl>
</expiry>
<listeners>
<listener>
<class>org.ehcache.events.LogCacheEventListener</class>
<event-firing-mode>SYNCHRONOUS</event-firing-mode>
<event-ordering-mode>ORDERED</event-ordering-mode>
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>UPDATED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
<events-to-fire-on>REMOVED</events-to-fire-on>
<events-to-fire-on>EVICTED</events-to-fire-on>
</listener>
</listeners>
<resources>
<heap unit="entries">2000</heap>
<offheap unit="MB">5</offheap>
<disk persistent="true" unit="MB">20</disk>
</resources>
</cache-template>
<!-- This cache tracks the timestamps of the most recent updates to particular
tables. It is important that the cache timeout of the underlying cache implementation
be set to a higher value than the timeouts of any of the query caches. In
fact, it is recommended that the the underlying cache not be configured for
expiry at all. -->
<cache alias="default-update-timestamps-region"
uses-template="default">
<expiry>
<none />
</expiry>
<heap unit="entries">6000</heap>
</cache>

<!-- This cache stores the actual objects pulled out of the DB by Hibernate. -->
<cache alias="default-query-results-region"
uses-template="default">
<expiry>
<ttl unit="seconds">600</ttl>
</expiry>
<heap unit="entries">2000</heap>
</cache>

</config>

4 – Code complements

On the entities you wnat to cache add the following annotations.

@javax.persistence.Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "you_region")

One the persistence joinning annotations like @ManyToOne, @ManyToMany an so on, you can cache the joinning datas

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@ManyToMany...

On the speific queries ypu wanna cache you might add

@org.springframework.data.jpa.repository.QueryHints(@javax.persistence.QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))

5 – Listener implementation

package org.ehcache.events;

import org.ehcache.event.CacheEvent;
import org.ehcache.event.CacheEventListener;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LogCacheEventListener implements CacheEventListener<Object, Object> {

public LogCacheEventListener() {
log.trace("Create Cache event logger");
}

@Override
public void onEvent(CacheEvent<? extends Object, ? extends Object> event) {
log.info("Cache event = {}, Key = {}, Old value = {}, New value = {}", event.getType(),
event.getKey(), event.getOldValue(), event.getNewValue());
}
}

Posted

in

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *