【问题标题】:Spring Boot + JPA2 + Hibernate - enable second level cacheSpring Boot + JPA2 + Hibernate - 启用二级缓存
【发布时间】:2015-10-13 15:51:08
【问题描述】:

我正在使用带有 JPA2 的 Spring Boot 1.2.5 来注释实体(并将休眠作为底层 JPA 实现)。

我想在该设置中使用二级缓存,因此实​​体被注释为@javax.persistence.Cacheable

我还在 application.properties 中添加了以下内容:

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=org.hibernate.cache.ehcache.EhCacheRegionFactory

在启动期间休眠抱怨缺少EhCacheRegionFactory 所以我也将这个添加到pom:

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

但像entityManager.find(Clazz.class, pk) 这样的查询仍然会触发数据库查询,而不是使用缓存数据。

知道缺少什么吗?

【问题讨论】:

  • 希望您在配置类中使用@EnableCaching 或在xml 文件中使用&lt;cache:annotation-driven /&gt; 启用缓存管理。
  • 虽然它只用于 Spring 缓存 - 我想在类级别使用 JPA2 缓存(更新问题以表明我正在使用@javax.persistence.Cacheable
  • 您好,我遵循了您和其他人提到的所有步骤,但仍然无法在休眠中启用二级缓存我使用的是 spring boot 和 hibernate 5.4.15 final jar,并且在 spring boot 中它正在给我 ehcache 2.10.6 jar。我收到以下警告“HHH020100:不推荐使用 Hibernate 的 Ehcache 二级缓存提供程序。”

标签: hibernate spring-boot jpa-2.0 second-level-cache


【解决方案1】:

总结一切(L2 缓存和查询缓存):

首先要做的是将缓存提供程序(我推荐使用 EhCache)添加到您的类路径中。

休眠

添加hibernate-ehcache 依赖项。该库包含现已停产的 EhCache 2。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>your_hibernate_version</version>
</dependency>

休眠>=5.3

在较新版本的 Hibernate 缓存中实现了 JSR-107 (JCache) API。所以需要 2 个依赖项 - 一个用于 JSR-107 API,第二个用于实际的 JCache 实现(EhCache 3)。

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

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.6.3</version>
    <scope>runtime</scope>
</dependency>

现在让我们转到 application.properties/yml 文件:

spring:
  jpa:
    #optional - show SQL statements in console. 
    show-sql: true 
    properties:
      javax:
        persistence:
          sharedCache: 
            #required - enable selective caching mode - only entities with @Cacheable annotation will use L2 cache.
            mode: ENABLE_SELECTIVE 
      hibernate:
        #optional - enable SQL statements formatting.
        format_sql: true 
        #optional - generate statistics to check if L2/query cache is actually being used.
        generate_statistics: true
        cache:
          #required - turn on L2 cache.
          use_second_level_cache: true
          #optional - turn on query cache.
          use_query_cache: true 
          region:
            #required - classpath to cache region factory.
            factory_class: org.hibernate.cache.ehcache.EhCacheRegionFactory 

对于 EhCache 3(或 Hibernate >=5.3),应该使用这个区域工厂:

factory_class: org.hibernate.cache.jcache.JCacheRegionFactory

您还可以为 Hibernate 启用 TRACE 级别日志记录以验证您的代码和配置:

logging:
  level:
    org:
      hibernate:
        type: trace

现在让我们继续看代码。要在您的实体上启用 L2 缓存,您需要添加这两个注释:

@javax.persistence.Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) //Provide cache strategy.
public class MyEntity {
  ...
}

注意 - 如果您想缓存 @OneToMany@ManyToOne 关系 - 在此字段上添加 @Cache 注释。

要在 spring-data-jpa 存储库中启用查询缓存,您需要添加正确的 QueryHint

public class MyEntityRepository implements JpaRepository<MyEntity, Long> {

  @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
  List<MyEntity> findBySomething(String something);

}

现在通过日志验证您的查询是否只执行一次,并记得关闭所有调试内容 - 现在您已完成。

注意 2 - 如果您想保持默认值而不在日志中收到警告,您也可以将 missing cache strategy 定义为 create

spring:
  jpa:
    properties:
      hibernate:
        javax:
          cache:
            missing_cache_strategy: create

【讨论】:

  • 如何为缓存的实体添加time to live?此外,二级缓存是默认驱逐或删除自身,还是在应用程序正常运行期间保持可用性?
  • pom.xml 中是否需要 hibernate-ehcachehibernate-jcache?我很困惑,因为我使用的是 Spring Boot 2.2 + Hibernate >6 和 EhCache 3。我不清楚它们是否会被用作替代品或替代品。特别是因为其他博客只提到了第一个并且不谈论hibernate-jcache。例如ehcache.org/documentation/2.8/integrations/hibernate.html
  • @LeO 你把两件事混为一谈了。有hibernate-echache-2hibernate-ehcache-3。第一个 (2) 是独立的缓存实现,现已过时。第二个 (3) 是 JSR-107 API(也称为 jcache)的实现。如果您使用的是 ehcache 版本。 3 需要两个依赖项(hibernate-jcache 和 hibernate-ehcache-3)。
  • @greperror 二级缓存在每次实体更改时自行驱逐。为了更改time to live,您需要通过@Bean public CacheManager cacheManager() 提供自定义cacheManager bean。关于缓存过期配置的 Ehcache 文档:ehcache.org/documentation/3.8/expiry
  • @LeO 从技术上讲 hibernate-ehcache (3) 在提供的范围内使用 javax.cache:cache-api 工件,因此您必须在 compile 范围内手动添加此工件。实际上hibernate-jcachecompiled 范围内有这种依赖关系+ 一些额外的记录器和hibernate-core 依赖关系。看看这些 maven 工件:mvnrepository.com/artifact/org.ehcache/ehcache/3.8.1mvnrepository.com/artifact/org.hibernate/hibernate-jcache/…
【解决方案2】:

经过更多的挖掘,这就是我在application.properties 中缺少的内容:

spring.jpa.properties.javax.persistence.sharedCache.mode=ALL

希望它可以帮助某人:)

【讨论】:

  • Thx Daimon,对于到目前为止的任何人,值得注意的是,除了此答案的配置之外,您还需要问题中的两个配置。
  • 最好设置spring.jpa.properties.javax.persistence.sharedCache.mode=ENABLE_SELECTIVE,因为只有这样你才会尊重你的@javax.persistence.Cacheable注解。
  • 我通过设置这个属性解决了这个问题:hibernate.cache.region.factory_class
  • Spring boot 1.5.9.RELEASE 出现错误:运行时发生异常。 null:InvocationTargetException:在类路径资源[o rg/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]中定义名称为“entityManagerFactory”的bean创建错误:调用init方法失败;嵌套异常是java。 lang.IllegalArgumentException:没有枚举常量 javax.persistence.SharedCacheMode.javax.persistence.SharedCacheMode.ALL
  • 据我所知,没有必要明确设置hibernate.cache.region.factory_classhibernate.cache.region.use_second_level_cache,因为如果只有一个RegionFactory 实现,org.hibernate.cache.internal.RegionFactoryInitiator 会自动执行此操作
【解决方案3】:

@Daimon我不太确定,是否

spring.jpa.properties.javax.persistence.sharedCache.mode=ALL

是最好的决定。

引用自Hibernate 20.2.1. Cache mappings documentation section

默认情况下,实体不属于二级缓存,我们建议您坚持此设置。但是,您可以通过在 persistence.xml 文件中设置 shared-cache-mode 元素或在配置中使用 javax.persistence.sharedCache.mode 属性来覆盖它。

ENABLE_SELECTIVE(默认值和推荐值):除非明确标记为可缓存,否则不会缓存实体。

那么,您是否没有使用 @javax.persistence.Cacheable 或者更确切地说是 @org.hibernate.annotations.Cache 注释所有受影响的实体?这可能会导致影响,即查询缓存尝试在二级缓存中查找受影响的实体但未成功,然后开始通过单个选择获取每个实体。

【讨论】:

  • 不,事实并非如此。 spring.jpa.properties.javax.persistence.sharedCache.mode 必须明确设置。无论是 ALL 还是不同的设置都是另一回事,与这个问题本身无关
  • 补充我的两分钱:使用 Spring Boot 1.4、Ehcache 和 Hibernate 5.1,您至少需要设置区域工厂和共享缓存模式。即使ENABLE_SELECTIVE 被记录为默认值,我也需要明确地将其设置为该值。
【解决方案4】:

你添加了吗

@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY) 

在您要缓存的类上?

【讨论】:

    【解决方案5】:

    您的类路径中应该有一个 ehcache.xml 文件。该文件应至少包含默认缓存策略。为了更容易调试,确保实体不会从缓存中被逐出:

    ehcache.xml:

    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:noNamespaceSchemaLocation="ehcache.xsd"
      Name="CacheManager" 
      maxBytesLocalHeap="250m">
    
    <defaultCache eternal="true"
    ...
    />
    
    <cache name="org.hibernate.cache.internal.StandardQueryCache"
           eternal="true"
    ...
    />
    

    为确保一切正常,您应该在应用程序启动期间拥有以下日志:

    Could not find a specific ehcache configuration for cache named [com.yourcompany.YourClass]; Using defaults.
    

    这意味着您的实体缓存注释已被正确读取,并且将使用默认缓存。

    如果您使用entityManager.find(Clazz.class, pk) 进行测试,则不会涉及查询缓存,而只是涉及实体缓存。查询缓存用于查询(em.createQuery(...) 和关系船

    另外,我使用 org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory,但我不知道哪个更好。

    【讨论】:

    • 虽然建议使用ehcache.xml,但这绝不是必要的。 Ehcache 将使用默认缓存配置,它为您提供 10.000 个元素和 120 秒的 TTL - 这没有调整,但对于许多人来说是一个足够好的起点。另请注意,拥有ehcache.xml 是不够的,您还必须定义适当的缓存以消除所有警告。
    【解决方案6】:

    您可以使用第三方缓存提供程序,包括 JCache、Ehcache、Gvava Cache、Hazelcast Cache、Caffeine Cache。

    请参考Quora上的这个答案,了解如何在 Spring boot 中启用和配置二级缓存。

    【讨论】:

    • 请在此处提供至少部分链接的详细信息,因为该链接将来可能会损坏。
    • 提供的链接描述了如何配置 Spring Boot 缓存,而不是 Hibernate。它们是不同的东西。
    猜你喜欢
    • 2019-06-11
    • 1970-01-01
    • 2012-12-12
    • 2011-09-11
    • 2013-09-05
    • 2017-03-31
    • 1970-01-01
    • 2015-02-06
    • 2015-05-14
    相关资源
    最近更新 更多