Spring Boot + JPA2 + Hibernate - включить кеш второго уровня

Я использую 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

Во время загрузки hibernate жаловался на отсутствие EhCacheRegionFactory, поэтому я также добавил это в pom:

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

Но все же запросы, такие как entityManager.find(Clazz.class, pk), запускают запрос БД вместо использования кэшированных данных.

Любая идея, что не хватает?

Ответ 1

Ну, после того, как я еще больше копал то, чего не хватало в application.properties:

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

Надеюсь, это поможет кому-то:)

Ответ 2

@Daimon Я не уверен,

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

- лучшее решение.

Цитируется из Hibernate 20.2.1. Раздел документации сопоставлений кэшей

По умолчанию объекты не входят в кеш второго уровня, и мы рекомендуем придерживаться этого параметра. Однако вы можете переопределить это, установив элемент режима shared-cache-mode в файл persistence.xml или используя свойство javax.persistence.sharedCache.mode в вашей конфигурации.

тогда

ENABLE_SELECTIVE (значение по умолчанию и рекомендуемое значение): объекты не кэшируются, если явно не помечены как кэшируемые.

Итак, может быть, вы не аннотировали все затронутые объекты с помощью @javax.persistence.Cacheable или, скорее, @org.hibernate.annotations.Cache? Это может привести к влиянию на то, что Query Cache попытался найти уязвимые объекты в кэше второго уровня без успеха, а затем начал извлекать каждую сущность одним нажатием.

Ответ 3

Для суммирования всего (кеш L2 и кеш запросов):

Первое, что нужно сделать, это добавить провайдера кэша (я рекомендую использовать EhCache) в ваш путь к классам.

В предыдущей версии Hibernate (до 5.3) это делается путем добавления этой зависимости. Эта зависимость содержит EhCache 2, которая в настоящее время прекращена.

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

В более новых версиях кэшей Hibernate следует использовать API JSR-107 (JCache). Таким образом, необходимо 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

Вы также можете включить ведение журнала уровня TRACE для Hibernate, чтобы проверить ваш код и конфигурацию:

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 - вы также можете определить отсутствующую стратегию кэширования как create если хотите остаться со значениями по умолчанию, не получая предупреждений в своих журналах:

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

Ответ 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(...) и для отношений ship

Кроме того, я использую org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory, но я не знаю, что лучше.

Ответ 6

Вы можете использовать сторонний поставщик кеша, среди которых JCache, Ehcache, Gvava Cache, Hazelcast Cache, Caffeine Cache.

Пожалуйста, обратитесь к этому ответу на Quora, чтобы узнать, как включить и настроить кэш второго уровня при загрузке Spring.