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

Dai*_*mon 28 hibernate second-level-cache jpa-2.0 spring-boot

我正在使用带有JPA2的Spring Boot 1.2.5来注释实体(并将hibernate作为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
Run Code Online (Sandbox Code Playgroud)

在启动期间,hibernate抱怨缺乏,EhCacheRegionFactory所以我也把它添加到pom:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)

但仍然是查询类似于entityManager.find(Clazz.class, pk)触发数据库查询而不是使用缓存数据.

知道缺少什么吗?

Dai*_*mon 31

经过一些挖掘,这里是我所缺少的application.properties:

spring.jpa.properties.javax.persistence.sharedCache.mode=ALL
Run Code Online (Sandbox Code Playgroud)

希望它可以帮助别人:)

  • 最好设置`spring.jpa.properties.javax.persistence.sharedCache.mode = ENABLE_SELECTIVE`因为只有这样你才会尊重你的`@javax.persistence.Cacheable`注释. (19认同)

Mic*_*mal 21

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

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

在以前的Hibernate版本(5.3之前的版本)中,它是通过添加hibernate-ehcache依赖项来完成的。该库包含EhCache 2,现已停产。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>your_hibernate_version</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

在较新版本的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>
Run Code Online (Sandbox Code Playgroud)

现在让我们转到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 using @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 
Run Code Online (Sandbox Code Playgroud)

对于EhCache 3,应使用该区域工厂:

factory_class: org.hibernate.cache.jcache.JCacheRegionFactory
Run Code Online (Sandbox Code Playgroud)

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

logging:
  level:
    org:
      hibernate:
        type: trace
Run Code Online (Sandbox Code Playgroud)

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

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

注意 -如果要缓存您的@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);

}
Run Code Online (Sandbox Code Playgroud)

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

注意2-您也可以定义缺少的缓存策略create就像您希望保留默认值而不会在日志中收到警告一样:

spring:
  jpa:
    properties:
      hibernate:
        javax:
          cache:
            missing_cache_strategy: create
Run Code Online (Sandbox Code Playgroud)

  • @LeO你正在混合两件事。有“hibernate-echache-2”和“hibernate-ehcache-3”。第一个 (2) 是独立的缓存实现,现已过时。第二个 (3) 是 JSR-107 API(也称为 jcache)的实现。如果您使用 ehcache 版本。3 需要两个依赖项(hibernate-jcache 和 hibernate-ehcache-3)。 (2认同)
  • @greperror 二级缓存每次实体更改时都会自行驱逐。为了更改“生存时间”,您需要通过“@Bean public CacheManager cacheManager()”提供自定义cacheManager bean。关于缓存过期配置的Ehcache文档:https://www.ehcache.org/documentation/3.8/expiry (2认同)
  • @LeO 从技术上讲 hibernate-ehcache (3) 在提供的范围内使用 `javax.cache:cache-api` 工件,因此您必须在 `compile` 范围内手动添加此工件。实际上,“hibernate-jcache”在“已编译”范围内具有此依赖项+一些额外的记录器和“hibernate-core”依赖项。只需看看这些 Maven 工件:https://mvnrepository.com/artifact/org.ehcache/ehcache/3.8.1,https://mvnrepository.com/artifact/org.hibernate/hibernate-jcache/5.4.12.Final (2认同)

小智 7

@Daimon我不确定,是否

spring.jpa.properties.javax.persistence.sharedCache.mode=ALL
Run Code Online (Sandbox Code Playgroud)

是最好的决定.

引自Hibernate 20.2.1.缓存映射文档部分

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

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

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