Search code examples
spring-boothibernateehcache-3

Is Hibernate 6 not compatible with Ehcache 3 for Spring Boot 3?


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.


Solution

  • 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 {
    }