Ответ 1
Ну, после того, как я еще больше копал то, чего не хватало в application.properties
:
spring.jpa.properties.javax.persistence.sharedCache.mode=ALL
Надеюсь, это поможет кому-то:)
Я использую 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)
, запускают запрос БД вместо использования кэшированных данных.
Любая идея, что не хватает?
Ну, после того, как я еще больше копал то, чего не хватало в application.properties
:
spring.jpa.properties.javax.persistence.sharedCache.mode=ALL
Надеюсь, это поможет кому-то:)
@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 попытался найти уязвимые объекты в кэше второго уровня без успеха, а затем начал извлекать каждую сущность одним нажатием.
Для суммирования всего (кеш 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
Вы добавили
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
в классе, который вы хотите кэшировать?
У вас должен быть файл 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, но я не знаю, что лучше.
Вы можете использовать сторонний поставщик кеша, среди которых JCache, Ehcache, Gvava Cache, Hazelcast Cache, Caffeine Cache.
Пожалуйста, обратитесь к этому ответу на Quora, чтобы узнать, как включить и настроить кэш второго уровня при загрузке Spring.