【问题标题】:Spring Boot 2.0 Hibernate 5 EhCache 3 with JCacheSpring Boot 2.0 Hibernate 5 EhCache 3 与 JCache
【发布时间】:2019-05-24 14:31:39
【问题描述】:

我正在尝试使用 EhCache 作为二级缓存设置 Hibernate,但 TTL 不起作用。

这是我的依赖项:

<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>

这是我的 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

这是我的 Entity 类的配置方式:

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

以及实体的 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);
}

我已将缓存配置为在 2 秒后过期,但调用 findByName 仍会使用缓存(在第一个之后没有打印 SQL 查询)。

这是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>

编辑: 我做了一些调试。我在org.ehcache.jsr107.ExpiryPolicyToEhcacheExpiry 中添加了一个断点:

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

由于某种原因,此持续时间是无限的。那么也许配置没有正确设置?我知道正在读取 xml,因为当我使其无效时(例如通过删除堆标记)我得到一个错误。

【问题讨论】:

  • 您有任何异常吗?你怎么知道它不起作用?
  • 我添加了ehcache.xml 配置文件,其 TTL 为 2 秒,但只有第一个方法调用正在打印查询,这意味着它正在使用缓存,但它不会过期。
  • 你可以尝试更新数据库并检查它是否仍在使用缓存数据或更新的数据?
  • 我已经更新了数值,不管我等了多久,数值都没有刷新。
  • 为什么返回 List 而不是 PersonEntity,ID 不是主键吗?

标签: java hibernate spring-boot ehcache-3


【解决方案1】:

我想我找到了问题的原因 - 您没有指定 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

在这种情况下,Hibernate 使用默认配置创建缓存。我的演示项目日志中的一个片段:

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'.

【讨论】:

  • 你知道这是在哪里记录的吗?这解决了我的问题。
  • @George here.
  • 感谢分享这些配置。我的配置错误,因为他们创建了两个同名的不同缓存,因此 ttl 无法正常工作。
【解决方案2】:

当您在实体顶部设置@Cacheable 注释时,它会创建一个区域,其中KEY 是实体的IDValue 是实体。上面的意思是如果你通过ID的键访问,你将命中缓存。如果您使用 spring 数据和 findById 它将命中缓存。如果你创建了一个 findByName 方法,那么访问将不会是按键树,因此它不会命中你的 Cacheable 注释定义的缓存区域。另一方面,它会命中查询缓存,但查询缓存位于完全不同的区域。而且从您的配置来看,您根本没有配置查询缓存。要使此方法完全命中任何缓存,您需要使用此属性添加它:

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

或者,您可以在存储库方法之上指定@Cacheable,这样定义一个新区域。

您可以配置默认缓存,这应该捕获 StandardQueryCache。

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

在EhCache2中你可以通过这个元素配置标准查询缓存:

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

不确定它在 ehcache 3 中的情况。我相信应该是一样的,因为 StandartQueryCache 类是 hibernate 包的一部分,而不是 ehcache 包的一部分。

我也认为你需要设置
hibernate.javax.cache.provider = org.ehcache.jsr107.EhcacheCachingProvider

【讨论】:

  • 我收到此错误:Error:(23, 33) java: cannot access net.sf.ehcache.CacheManager class file for net.sf.ehcache.CacheManager not found
  • 我相信这对于 Ehcache 2 来说已经过时了。
  • 是的,你是对的。这是ehcach2。尝试添加 hibernate.javax.cache.provider = org.ehcache.jsr107.EhcacheCachingProvider 还有一个非休眠的提供者,目前尚不清楚 Spring Boot 自动配置默认选择哪一个。可能值得设置。
  • 我还可以看到您已将查询修改为 findByName。缓存区域由 ID 定义,因此 ID 是关键。如果您按 NAME 选择,除非您使用 Cacheable 注释该方法,否则您将不会命中缓存区域,然后您将有效地创建一个与“com.sample.PersonEntity”不同的新缓存区域。将方法更改为 findById 并查看您是否正在访问缓存。
猜你喜欢
  • 1970-01-01
  • 2018-07-14
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-10
相关资源
最近更新 更多