In a Spring Boot 3 application I have the following dependencies:
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jcache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>${ehcache3.version}</version>
</dependency>
Then, in the application.yml the following properties are set:
spring.jpa.properties:
-hibernate.generate_statistics: true
-hibernate.cache.use_second_level_cache: true
-hibernate.cache.region.factory_class: "jcache"
-hibernate.javax.cache.provider: "org.ehcache.jsr107.EhcacheCachingProvider"
And at last, @EnableCaching
is applied to a config class. But all the configuration above doesn't seem to work, since Hibernate still makes a database trip for each request for the following entity:
@Entity
@Access(AccessType.FIELD)
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "email_status")
public class EmailStatus implements Serializable {
//...
}
The query and statistics output is always the same:
select
e1_0.email_status_id,
e1_0.description
from
email_status e1_0
where
e1_0.description=?
21:45:12 TRACE - [nio-8087-exec-2] o.h.o.j.bind : binding parameter [1] as [VARCHAR] - [PENDING]
...
21:45:12 INFO - [nio-8087-exec-2] o.h.e.i.StatisticalLoggingSessionEventListener : Session Metrics {
12566 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
42664 nanoseconds spent preparing 1 JDBC statements;
73055 nanoseconds spent executing 1 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
301863 nanoseconds spent performing 1 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
87958 nanoseconds spent executing 1 flushes (flushing a total of 1 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}
If I don't use any Hibernate specific settings and just let spring-boot-starter-cache
do its work, annotating the entity with org.springframework.cache.annotation.Cacheable
caching works - maybe not quite so performant, but at least is works.
Hibernate's documentation here tells in the infobox that compatible JCache implementations can be found on the JPC website. The link to the supported Ehcache implementation brings you to this 10 year old Ehcache 2.x version. That can't be serious, or though?
Why can't I find any actual documentation of how to configure Hibernate 6 with Ehcache 3 for a Spring Boot 3 application? Is it possible, that this is a non working combination? All I find are outdated documentations or fiddeling examples without any context. However, after spending a few hours trying to get the thing working, I'm giving up. Either this isn't possible at all, or I'm just too dumb.
If anybody knows how to set up a proper Ehcache 3 for Hibernate 6 in Spring Boot 3, that would really be wonderful. Many thanks.
Try to use this instead of org.springframework.cache.annotation.Cacheable
@jakarta.persistence.Cacheable
Here is the minimum configuration you need to add. Besides spring-data-jpa
, there are few dependencies required.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jcache</artifactId>
<version>6.3.1.Final</version>
</dependency>
Also you need to add these configuration to application.properties
to enable 2nd level cache.
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=jcache
spring.jpa.hibernate.javax.cache.provider=org.ehcache.jsr107.EhcacheCachingProvider
On the entity class level, use this to enable cache
@jakarta.persistence.Cacheable
@org.hibernate.annotations.Cache
public class EmailStatus {
}