Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot + JPA2 + Hibernate - enable second level cache

I'm using Spring Boot 1.2.5 with JPA2 to annotate entities (and hibernate as underlaying JPA implementation).

I wanted to use second level cache in that setup, so entities were annotated with @javax.persistence.Cacheable

I also added following in application.properties:

spring.jpa.properties.hibernate.cache.use_second_level_cache=true spring.jpa.properties.hibernate.cache.use_query_cache=true spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory 

During bootup hibernate complained about lack of EhCacheRegionFactory so I also added this to pom:

<dependency>     <groupId>org.hibernate</groupId>     <artifactId>hibernate-ehcache</artifactId> </dependency> 

But still queries like entityManager.find(Clazz.class, pk) are firing DB query instead of using cached data.

Any idea what is missing?

like image 309
Daimon Avatar asked Jul 23 '15 11:07

Daimon


People also ask

How do I enable the second level cache in hibernate spring boot?

For Enabling the second level of cache we have to made following change to hibernate configuration file. 1. Cache Strategy using with Annotation as some changes made to the Model class also. @Cacheable @Cache(usage = CacheConcurrencyStrategy.

Do you want to use hibernate 2nd level cache?

Why Is a Second-Level Cache Important for Hibernate? A second-level cache improves application performance with regard to persistence for all sessions created with the same session factory.


2 Answers

To sum everything (L2 cache and query cache) up:

The first thing to do is to add cache provider (I recommend using EhCache) to your classpath.

Hibernate < 5.3

Add the hibernate-ehcache dependency. This library contains EhCache 2 which is now discontinued.

<dependency>     <groupId>org.hibernate</groupId>     <artifactId>hibernate-ehcache</artifactId>     <version>your_hibernate_version</version> </dependency> 

Hibernate >=5.3

In newer versions of Hibernate caches implementing JSR-107 (JCache) API should be used. So there're 2 dependencies needed - one for JSR-107 API and the second one for the actual JCache implementation (EhCache 3).

<dependency>      <groupId>org.hibernate</groupId>      <artifactId>hibernate-jcache</artifactId>      <version>your_hibernate_version</version> </dependency>  <dependency>     <groupId>org.ehcache</groupId>     <artifactId>ehcache</artifactId>     <version>3.6.3</version>     <scope>runtime</scope> </dependency> 

Now let's move on to application.properties/yml file:

spring:   jpa:     #optional - show SQL statements in console.      show-sql: true      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: true          #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            region:             #required - classpath to cache region factory.             factory_class: org.hibernate.cache.ehcache.EhCacheRegionFactory  

For EhCache 3 (or Hibernate >=5.3) this region factory should be used:

factory_class: org.hibernate.cache.jcache.JCacheRegionFactory 

You can also enable TRACE level logging for Hibernate to verify your code and configuration:

logging:   level:     org:       hibernate:         type: trace 

Now let's move on to the code. To enable L2 caching on your entity you need to add those two annotations:

@javax.persistence.Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) //Provide cache strategy. public class MyEntity {   ... } 

Note - if you want to cache your @OneToMany or @ManyToOne relation - add @Cache annotation over this field as well.

And to enable query cache in your spring-data-jpa repository you need to add proper QueryHint.

public class MyEntityRepository implements JpaRepository<MyEntity, Long> {    @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))   List<MyEntity> findBySomething(String something);  } 

Now verify via logs if your query is executed only once and remember to turn off all the debug stuff - now you're done.

Note 2 - you can also define missing cache strategy as create if you want to stay with defaults without getting warnings in your logs:

spring:   jpa:     properties:       hibernate:         javax:           cache:             missing_cache_strategy: create 
like image 62
Michał Stochmal Avatar answered Sep 17 '22 15:09

Michał Stochmal


Well after some more digging here's what I was missing in application.properties:

spring.jpa.properties.javax.persistence.sharedCache.mode=ALL 

Hope it helps someone :)

like image 29
Daimon Avatar answered Sep 21 '22 15:09

Daimon