简体   繁体   English

带有JCache的Spring Boot 2.0 Hibernate 5 EhCache 3

[英]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. 我正在尝试使用EhCache将Hibernate设置为第二级缓存,但是TTL无法正常工作。

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: 这是我的YAML配置:

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类的配置方式:

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

And the JpaRepository for the entity: 以及实体的JpaRepository:

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). 我已将缓存配置为在2秒后过期,但是调用findByName仍会使用缓存(在第一个查询之后没有打印SQL查询)。

Here's the ehcache.xml file: 这是ehcache.xml文件:

<?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 : 我在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. 我知道正在读取xml,因为当我使它无效时(例如,通过删除堆标记),我得到一个错误。

在此处输入图片说明

I think I found the cause of the issue - you didn't specify a location of the ehcache.xml file: 我想我找到了问题的原因-您未指定ehcache.xml文件的位置:

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. 在这种情况下,Hibernate将使用默认配置创建一个缓存。 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. 当您在实体顶部设置@Cacheable批注时,它将创建一个区域,其中KEY是实体的ID ,而Value是实体。 The above mean that you will hit the cache if you access by key which is the ID . 上面的意思是,如果您通过ID (即密钥)进行访问,则会访问缓存。 If you use spring data and findById it will hit the cache. 如果您使用spring数据和findById,它将访问缓存。 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. 如果创建方法findByName,则将无法通过键trere进行访问,然后才能访问您的Cacheable批注定义的缓存区域。 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. 或者,您可以在存储库方法的顶部指定@Cacheable,从而定义一个新区域。

You can configigure default cache, this should capture the StandardQueryCahache. 您可以配置默认缓存,这应该捕获StandardQueryCahache。

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

In EhCache2 you can configure the standard query cache through this element: 在EhCache2中,您可以通过以下元素配置标准查询缓存:

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

Not sure how it is in ehcache 3 though. 虽然不确定在ehcache 3中如何。 I believe it should be the same, because the StandartQueryCache class is part of the hibernate package and not part of the ehcache package. 我相信应该是一样的,因为StandartQueryCache类是hibernate包的一部分,而不是ehcache包的一部分。

I also think you need to set 我也认为你需要设定
hibernate.javax.cache.provider = org.ehcache.jsr107.EhcacheCachingProvider hibernate.javax.cache.provider = org.ehcache.jsr107.EhcacheCachingProvider

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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