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

时间:2015-07-23 11:12:39

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

我正在使用带有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

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

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

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

知道缺少什么吗?

6 个答案:

答案 0 :(得分:27)

经过多次挖掘,我在application.properties中遗漏了什么:

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

希望它可以帮助某人:)

答案 1 :(得分:7)

@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注释所有受影响的实体?这可能会导致影响,查询缓存尝试在二级缓存中查找受影响的实体但没有成功,然后开始通过单个选择获取每个实体。

答案 2 :(得分:5)

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

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

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

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

在较新版本的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 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 

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

factory_class: org.hibernate.cache.jcache.JCacheRegionFactory

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

logging:
  level:
    org:
      hibernate:
        type: trace

现在让我们转到代码。要在您的实体上启用二级缓存,您需要添加这两个注释:

@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

答案 3 :(得分:2)

你添加了

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

关于要缓存的类?

答案 4 :(得分:0)

您的类路径中应该有一个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,但我不知道哪个更好。

答案 5 :(得分:0)

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

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