简体   繁体   中英

Spring Boot 2.0 Hibernate 5 EhCache 3 with JCache

I'm trying to setup Hibernate with EhCache as the second level cache but the TTL is not working.

Here are my dependencies:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

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

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

<dependency>
  <groupId>javax.cache</groupId>
  <artifactId>cache-api</artifactId>
</dependency>

Here's my YAML configuration:

spring:
  jpa:
    show-sql: true
    properties:
      hibernate:
        dialect: Dialect
        cache:
          use_second_level_cache: true
          region.factory_class: org.hibernate.cache.jcache.JCacheRegionFactory
          use_query_cache: true
  cache:
    jcache:
      config: classpath:ehcache.xml

Here's how my Entity class is configured:

@Entity
@javax.persistence.Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class PersonEntity {
  //
}

And the JpaRepository for the entity:

public interface PersonRepository extends JpaRepository<PersonEntity, Integer> {
  @org.springframework.data.jpa.repository.QueryHints({
      @javax.persistence.QueryHint(name = "org.hibernate.cacheable", value = "true")
  })
  List<PersonEntity> findByName(String name);
}

I've configured the cache to expire in 2 seconds, but calling findByName still uses the cache (there are no SQL Queries printed after the first one).

Here's the ehcache.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.ehcache.org/v3">

  <cache-template name="simple">
    <expiry>
      <ttl>2</ttl>
    </expiry>
    <heap>100</heap>
  </cache-template>

  <cache alias="com.sample.PersonEntity" uses-template="simple"/>

</config>

EDIT: I've done some debugging. I've added a break point in org.ehcache.jsr107.ExpiryPolicyToEhcacheExpiry :

javax.cache.expiry.Duration duration = this.expiryPolicy.getExpiryForCreation();

This duration is INFINITE for some reason. So maybe the configuration is not set properly? I know the xml is being read because when I invalidate it (by removing heap tag for example) I get an error.

在此处输入图片说明

I think I found the cause of the issue - you didn't specify a location of the ehcache.xml file:

spring:
  jpa:
    properties:
      hibernate:
        javax.cache:
          provider: org.ehcache.jsr107.EhcacheCachingProvider
          uri: classpath:ehcache.xml
        cache:
          use_second_level_cache: true
          region.factory_class: jcache
          use_query_cache: true

in this case Hibernate creates a cache with default configuration. A fragment from my demo project log:

17:15:19 WARN [main] org.hibernate.orm.cache: HHH90001006: Missing cache[user] was created on-the-fly. The created cache will use a provider-specific default configuration: make sure you defined one. You can disable this warning by setting 'hibernate.javax.cache.missing_cache_strategy' to 'create'.

When you set your @Cacheable annotation on top of your entity it creates a region where the KEY is the ID of the entity and the Value is the entity. The above mean that you will hit the cache if you access by key which is the ID . If you use spring data and findById it will hit the cache. If you create a method findByName the access will not be by key trerefore it will not hit the cache region defined by your Cacheable annotation. On the other hand it will hit the query cache, but the query cache is in entirely different region. And judging from your configuration you have not configured query cache at all.For this method to hit any cache at all you need to add it using this property:

spring:jpa:properties:hibernate:cache:use_query_cache: true

Alternativly you can specify @Cacheable on top of the repository method this way define a new region.

You can configigure default cache, this should capture the StandardQueryCahache.

<defaultCache 
    maxElementsInMemory="10000"
    eternal="false"
    timeToIdleSeconds="3600"
    timeToLiveSeconds="3600">
  </defaultCache>

In EhCache2 you can configure the standard query cache through this element:

  <cache
name="org.hibernate.cache.internal.StandardQueryCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600">

Not sure how it is in ehcache 3 though. I believe it should be the same, because the StandartQueryCache class is part of the hibernate package and not part of the ehcache package.

I also think you need to set
hibernate.javax.cache.provider = org.ehcache.jsr107.EhcacheCachingProvider

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM