Spring Boot + JPA2 + Hibernate - 启用二级缓存

Spring Boot + JPA2 + Hibernate - enable second level cache

我正在使用 Spring Boot 1.2.5 和 JPA2 来注释实体(并将休眠作为底层 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) 这样的查询仍然触发数据库查询而不是使用缓存数据。

知道缺少什么吗?

您的类路径中应该有一个 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(...) 和关系 ship

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

好吧,在进一步挖掘之后,这就是我在 application.properties 中遗漏的内容:

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

希望对大家有所帮助:)

@Daimon我不是很确定,是否

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

是最好的决定。

引自Hibernate 20.2.1. Cache mappings documentation section

By default, entities are not part of the second level cache and we recommend you to stick to this setting. However, you can override this by setting the shared-cache-mode element in your persistence.xml file or by using the javax.persistence.sharedCache.mode property in your configuration.

ENABLE_SELECTIVE (Default and recommended value): entities are not cached unless explicitly marked as cacheable.

所以,有没有可能您没有用 @javax.persistence.Cacheable 或 @org.hibernate.annotations.Cache 注释所有受影响的实体?这可能会导致影响,即查询缓存尝试在二级缓存中查找受影响的实体但没有成功,然后开始通过单个 select.

获取每个实体

你添加了吗

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

关于 class 你想缓存吗?

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

请参阅 Quora 上的此答案以了解如何在 Spring 引导中启用和配置二级缓存。

总结所有内容(二级缓存和查询缓存):

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

休眠 < 5.3

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

现在让我们继续申请。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